Почему я не могу просто добавить индекс, который включает все столбцы? - PullRequest
34 голосов
/ 27 марта 2011

У меня есть таблица в базе данных SQL Server, по которой я хочу иметь возможность искать и извлекать данные как можно быстрее. Меня не волнует, сколько времени занимает вставка в таблицу, меня интересует только скорость, с которой я могу получать данные.

Проблема в том, что к таблице обращаются с 20 или более различными типами запросов. Это затрудняет добавление индекса, специально разработанного для каждого запроса. Вместо этого я рассматриваю просто добавление индекса, который включает ВСЕ столбцы таблицы. Это не то, что вы обычно делаете в «хорошем» дизайне базы данных, поэтому я предполагаю, что есть веская причина, почему я не должен этого делать.

Может кто-нибудь сказать мне, почему я не должен этого делать?

ОБНОВЛЕНИЕ: я забыл упомянуть, мне также все равно размер моей базы данных. Ничего страшного, это означает, что размер моей базы данных будет больше, чем нужно до

Ответы [ 7 ]

71 голосов
/ 27 марта 2011

Прежде всего, индекс в SQL Server может содержать не более 900 байтов в своей записи индекса.Уже одно это делает невозможным иметь индекс со всеми столбцами.

Больше всего: такой индекс вообще не имеет смысла.Чего вы пытаетесь достичь ??

Примите во внимание следующее: если у вас есть индекс на (LastName, FirstName, Street, City), этот индекс не сможет использоваться для ускорения запросов на

  • FirstName один
  • City
  • Street

Этот индекс будет полезен для поиска по

  • (LastName), или
  • (LastName, FirstName), или
  • (LastName, FirstName, Street), или
  • (LastName, FirstName, Street, City)

, нона самом деле больше ничего - конечно, нет, если вы ищете просто Street или просто City!

Порядок столбцов в вашем индексе имеет большое значение, и оптимизатор запросов не может просто использовать любой столбецгде-то в середине индекса для поиска.

Рассмотрим вашу телефонную книгу: ее порядок, вероятно, LastName, FirstName, возможно Street.Так поможет ли этот индекс найти всех "Джо" в вашем городе?Все люди, живущие на "главной улице" ??Нет, сначала вы можете искать по LastName, а затем получить более конкретный набор данных.Наличие индекса по всему не помогает ускорить поиск по всем столбцам вообще .

Если вы хотите иметь возможность поиска по Street - вам нужно добавить отдельныйиндекс на (Street) (и, возможно, другой столбец или два, которые имеют смысл).

Если вы хотите иметь возможность поиска по Occupation или как-то еще - вам нужен другой конкретный индекс для этого.

Тот факт, что ваш столбец существует в индексе, не означает, что это ускорит все поиски по этому столбцу!

Главное правило: используйте как можно меньше индексов - слишком много индексов может быть дажехуже для системы, чем отсутствие индексов вообще ... создать свою систему, отслеживать ее производительность и находить те запросы, которые стоят больше всего, - а затем оптимизировать их, например, путем добавления индексов.

Не просто слепо индексировать каждый столбец только потому, что вы можете - это гарантия плохой производительности системы - любой индекс также требует обслуживания и обслуживания, поэтому, чем больше у вас индексов, тем больше будет INSERT, UPDATE иОперации DELETE пострадают (станут медленнее), поскольку все эти индексы должны быть обновлены.

8 голосов
/ 27 марта 2011

У вас есть фундаментальное недопонимание того, как работают индексы.

Прочтите это объяснение ", как работают многоколонные индексы ".

Следующий вопрос, который у вас может возникнуть, этопочему бы не создать один индекс на столбец - но это также тупик, если вы попытаетесь достичь максимальной производительности.

Вам может показаться, что это утомительная задача 1012 *, но я бы сказал, что эта задача требуется для тщательного индексирования.Небрежное индексирование наносит ответный удар, как в этом примере .

Примечание: я твердо убежден, что правильное индексирование окупается, и я знаю, что у многих людей возникают те же самые вопросы, что и у вас.Вот почему я пишу бесплатную книгу об этом.Ссылки выше ссылаются на страницы, которые могут помочь вам ответить на ваш вопрос.Однако вы также можете прочитать его с начала .

2 голосов
/ 27 марта 2011

Если это операция типа хранилища данных, где запросы высоко оптимизированы для запросов READ, и если у вас есть 20 способов распространения данных, например,

предложение WHERE включает в себя ..

 Q1: status, type, customer
 Q2: price, customer, band
 Q3: sale_month, band, type, status
 Q4: customer
 etc

И у вас есть достаточно места для быстрого хранения, затем всеми средствами создайте индекс для КАЖДОГО отдельного столбца, отдельно . Таким образом, таблица из 20 столбцов будет иметь 20 индексов, по одному на каждый отдельный столбец . Я мог бы, вероятно, сказать, чтобы игнорировать битовые столбцы или столбцы с низкой кардинальностью, но поскольку мы заходим так далеко, зачем беспокоиться (с этим предупреждением). Они просто будут сидеть и перетекать в ПИСЬМЕННОЕ время, но если вас не волнует эта часть картины, тогда у нас все хорошо.

Анализируйте ваши 20 запросов, и если у вас есть горячие запросы (самые горячие), которые все еще не будут выполняться быстрее, спланируйте их с помощью SSMS (нажмите Ctrl-L) с одним запросом в окне запросов. Он скажет вам, какой индекс может помочь этим запросам - просто создайте его; создайте их все, полностью помня, что это снова добавляет к стоимости записи, размеру файла резервной копии, времени обслуживания БД и т. д.

2 голосов
/ 27 марта 2011

... если вы добавите индекс, содержащий все столбцы, и запрос фактически сможет использовать этот индекс, он будет сканировать его в порядке первичного ключа. Что означает поражение почти каждой записи. Среднее время поиска будет O (n / 2) .. так же, как попадание в фактическую базу данных.

Вам нужно прочитать лот bit об индексах.

Это может помочь, если вы считаете, что индекс таблицы немного похож на словарь в C #.

var nameIndex = new Dictionary<String, List<int>>();

Это означает, что столбец имени проиндексирован и вернет список первичных ключей.

var nameOccupationIndex = new Dictionary<String, List<Dictionary<String, List<int>>>>();

Это означает, что имя столбца + столбцы занятия индексируются. Теперь представьте, что индекс содержит 10 различных столбцов, вложенных настолько глубоко, что содержит каждую строку в вашей таблице.

Имейте в виду, это не совсем так. Но это должно дать вам представление о том, как могут работать индексы, если они реализованы в C #. Вам нужно создать индексы, основанные на одном или двух ключах, к которым часто обращаются, чтобы индекс был более полезным, чем сканирование всей таблицы.

2 голосов
/ 27 марта 2011

Вместо этого я рассматриваю простое добавление индекса, включающего ВСЕ столбцы таблицы.

Это всегда плохая идея.Индексы в базе данных - это не какая-то фея пыли, которая работает волшебным образом.Вы должны проанализировать свои запросы и в соответствии с тем, что и как запрашивается, добавить индексы.

Это не так просто, как "добавить все в индекс и вздремнуть"

0 голосов
/ 27 марта 2011

1) размер, индекс, по существу, создает копию данных в этом столбце в некоторой легко доступной для поиска структуре, такой как двоичное дерево (я не знаю спецификаций SQL Server).2) Вы упомянули скорость, к индексным структурам добавить медленнее.

0 голосов
/ 27 марта 2011

Этот индекс будет идентичен вашей таблице (возможно, отсортирован в другом порядке).
Он не ускорит ваши запросы.

...