Помощь в понимании нескольких столбцов в индексе? - PullRequest
5 голосов
/ 16 сентября 2009

Предположим, у меня есть таблица с именем "таблица", и у меня есть 3 столбца, a, b и c.

Что значит иметь некластеризованный индекс для столбцов a, b?

Является ли некластеризованный индекс для столбцов a, b таким же, как некластеризованный индекс для столбцов b, a? (Обратите внимание на порядок).

Кроме того, является ли некластеризованный индекс для столбца a таким же, как некластеризованный индекс для a, c?

Я смотрел на производительность sqlserver веб-сайта, и у них были эти сценарии dmv, в которых он сообщал бы вам, если у вас перекрывающиеся индексы, и я полагаю, что он говорил, что наличие индекса на a такое же, как a, b, поэтому излишний. Это правда об индексах?

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

Великие объяснения. Должен ли я превратить это в вики и изменить объяснение индекса заголовка?

Ответы [ 5 ]

16 голосов
/ 16 сентября 2009

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

Кластеризованные и некластеризованные

Это относится к физическому расположению таблицы на диске. Кластерный индекс работает путем сортировки физических страниц и строк в таблице на диске на основе определения индекса. Некластеризованные индексы используют отдельное расположение на диске для хранения копии столбцов в индексе (и только этих столбцов), а также указателя на исходные записи. По этой причине кластерные индексы часто работают быстрее, потому что они всегда будут покрывать любые данные, которые вам нужны в запросе. Однако вы получаете только один из них, потому что в противном случае вы дублируете всю таблицу. Также важно знать, что добавление некластеризованных индексов в таблицу на самом деле замедляет операции записи, такие как вставки и обновления, потому что база данных должна перестраивать индекс или, по крайней мере, определенные страницы в индексе.

Индекс заказа

Индекс для (A,B) равен , а не такой же, как для (B,A). Если в первом случае записи в индексе упорядочены сначала по столбцу A, а столбец B влияет только на порядок индекса, если у вас есть повторяющиеся значения для A. Поиск по индексу только со значением столбца B не поможет вам, потому что вам все равно нужно просмотреть каждую запись в индексе, чтобы найти все совпадающие значения в B. Во втором случае происходит обратное: записи упорядочиваются сначала по столбцу B, а столбец A помогает только при наличии повторяющихся значений для A. Поиск по этому индексу только по столбцу A не поможет.

Индексы покрытия

Иногда база данных может полностью выполнить требования запроса из индекса. В этом случае говорят, что индекс является «покрывающим» индексом для этого запроса. Это выгодно, потому что индексы часто кэшируются в памяти, и поэтому базе данных, возможно, вообще не нужно делать диск. Чтобы понять это, представьте индекс на (A,B), где очень мало повторяющихся значений для A. Включение A в индекс кажется расточительным, если только у вас нет часто выполняющегося запроса, который ищет определенное значение A и также нуждается в B. Этот индекс теперь сохранит много работы, возвращаясь к исходной таблице для получения B.

Избирательность

Селективность - это значение от 0 до 1 (часто выражается в процентах), которое указывает, насколько уникальным является каждое значение в индексе. Селективность 1 или 100% означает, что дубликатов нет. Селективность 0 означает, что в столбце есть только одно значение. Как правило, более высокая селективность (приближающаяся к 1) лучше для индексов.

Чтобы продемонстрировать это, подумайте о том, что произойдет с индексом низкой селективности. Например, вы пытаетесь ускорить запрос, добавив индекс к битовому столбцу в таблице с 10000 записями. В этом случае (при условии равномерного распределения) селективность составляет .5. Вы выполняете запрос, и индекс возвращает 5000 записей. Но каждая из этих записей по-прежнему должна возвращаться к исходной таблице, и, поскольку порядок индекса не совпадает с порядком таблицы, необходимо выполнить множество отдельных проверок в таблице. Вместо этого, скорее всего, быстрее просто просмотреть всю таблицу от начала до конца, чтобы получить необходимые данные.

Избирательность объясняет, почему вы хотите кластеризоваться на первичном ключе. Так как кластеризованный индекс сообщает базе данных, как упорядочить таблицу, выбор степени ниже 100% означает, что запрос должен будет сканировать таблицу чаще. Кластеризация по первичному ключу обеспечивает идеальную избирательность. А поскольку этот первичный ключ часто используется в качестве указателя записи в других индексах, вы хотите, чтобы он был как можно меньше (т. Е. Столбец целочисленных идентификаторов).

Здесь есть хорошая статья о селективности и индексации:
http://www.akadia.com/services/ora_index_selectivity.html

Sargable

Это относится к тому, может ли база данных использовать определенный фильтр с индексом.

Как мы показали, индексы обычно работают, сначала сортируя данные в определенном порядке, так что при поиске в этом индексе можно использовать что-то эффективное, например, поиск по дереву, а не более медленный линейный поиск. Все, что нельзя эффективно сравнить с отсортированными данными, нельзя использовать с индексом. Хорошим примером является оператор LIKE. Это прощается:

SELECT * FROM [Table] WHERE [Column] LIKE @Value + '%'

но это не sargable:

SELECT * FROM [Table] WHERE [Column] LIKE '%' + @Value + '%'

Некоторые другие вещи, которые могут сделать фильтр невозможным, - это недетерминированные функции (а их больше, чем вы думаете).

Индексы по столбцам

Распространенная ошибка, которую я видел, - иметь отдельный индекс для каждого столбца в таблице. Например, кто-то возьмет таблицу со столбцами (A,B,C,D) и создаст четыре отдельных индекса, по одному для A, B, C, D, полагая, что они теперь проиндексировали каждый столбец, и поэтому каждый запрос должен быть быстрым. На самом деле, это редко бывает полезно по причинам, которые, я надеюсь, я уже объяснил, и часто будет усугублять, а не улучшать, потому что базе данных теперь нужно будет обновлять эти индексы для каждого изменения данных.

3 голосов
/ 16 сентября 2009

A некластеризованный индекс в (a, b) является «копией» части таблицы, строки которой отсортированы по a, затем по b и содержат ссылку на исходную строку .

Это помогает запускать такие запросы:

SELECT  *
FROM    mytable
WHERE   a = @A
        AND b = @B

, это:

SELECT  *
FROM    mytable
ORDER BY
        a, b

, это:

SELECT  *
FROM    mytable
WHERE   a = @A
ORDER BY
        b

и многие другие.

Например, у нас есть такая таблица:

#       col1    col2    col3
1       1       1       1
2       1       4       8
3       7       2       3
4       3       3       9
5       8       9       4
6       2       2       7
7       5       3       5
8       3       9       4

Если мы создадим индекс для (col2, col3), он будет содержать следующие данные:

col2    col3    #
1       1       1
2       3       3
2       7       6
3       5       7
3       9       4
4       8       2
9       4       5
9       4       8

, т.е. е. отсортировано сначала по col2, затем по col3, затем по ссылке на строку.

Легко видеть, что этот индекс также является индексом для col2 (сортировка по (col2, col3) подразумевает сортировку только по col2).

Порядок имеет значение, поэтому, если мы создадим индекс для (col3, col2), строки будут отсортированы по-разному:

col2    col3    #
1       1       1
2       3       3
9       4       5
9       4       8
3       5       7
2       7       6
4       8       2
3       9       4

Этот индекс является индексом и для col3.

Если мы хотим найти строки в определенном диапазоне (col2, col3), мы просто берем фрагмент из упорядоченных данных:

SELECT  col2, col3
FROM    mytable
WHERE   col2 BETWEEN 2 AND 3

col2    col3    #
1       1       1
----
2       3       3
2       7       6
3       5       7
3       9       4
----
4       8       2
9       4       5
9       4       8

Легко видеть, что мы не можем использовать этот фрагмент на col3, используя этот индекс, поскольку col3 не упорядочен сам по себе.

Упомянутая выше "ссылка" - это RID строки (указатель на место в табличном пространстве), если таблица сама не кластеризована, или значение ключа кластера таблицы, если таблица кластеризована .

A кластеризованный индекс не создает теневую копию значений. Вместо этого он переставляет сами строки таблиц.

Если вы создадите кластерный индекс на (col2, col3) выше, он просто переставит строки таблицы:

#       col1    col2    col3
1       1       1       1
3       7       2       3
6       2       2       7
7       5       3       5
4       3       3       9
2       1       4       8
5       8       9       4
8       3       9       4

Кластеризация или некластеризация, следовательно, является методом хранения, а не индексом.

В Oracle это называется index-organized table (строки отсортированы), в отличие от heap-organized table (строки не отсортированы).

2 голосов
/ 16 сентября 2009

Думайте об индексе как о телефонной книге. Обычно телефонные книги упорядочены по фамилии, имени, улице. Поэтому, если вы хотите найти номер телефона Джо Смита, 101 Мэйн-стрит, вы открываете телефонную книгу в S для Смита, а затем ищите всех Джо под Смитом, ищите Джо Смита, который живет на 101 Мэйн-стрит, и вы найти номер телефона.

Телефонная книга может быть заказана по-разному, например, по улице, имени, фамилии. Тогда вы сначала посмотрите на главную улицу, затем на Джо и, наконец, на Смита. Если вы хотите найти номер только одного человека, это будет одинаково быстро.

Разница становится важной, если вы хотите перечислить номера телефонов всех людей, которые живут на Мэйн-стрит и чье имя Джо. С обычной телефонной книгой это неприятно: вам нужно перебрать все фамилии, узнать Джо с этой фамилией и узнать, живут ли они на Мэйн-стрит. Для этого вам нужно просмотреть всю телефонную книгу. Но если порядок индексов - улица, имя, фамилия, задача почти тривиальна: найдите главную улицу, Джо, и скопируйте все фамилии и их номера телефонов. Намного быстрее.

Кроме того, тот факт, что в телефонных книгах перечислены улицы, также не имеет значения, если вас интересуют только названия. Если вы хотите найти телефонные номера всех Джо Смитов, вам нужна телефонная книга, упорядоченная по фамилии, имени (или имени, фамилии). Вам все равно, есть ли в телефонной книге все заказанные Джо Смитс по улице или нет. В этом смысле индекс (фамилия, имя, улица) включает в себя индекс (фамилия, имя).

Итак: индекс (a, b, c) не равен (c, a, b), и если у вас есть (a, c), вам не нужен другой (a)

2 голосов
/ 16 сентября 2009

Является некластеризованным индексом для столбцов a, b такой же, как некластеризованный индекс на столбцы б, а? (Обратите внимание на порядок).

НЕТ! Порядок важен. Если у вас есть некластеризованный индекс для (a, b), вы можете использовать его, если в предложении WHERE есть ограничение для a и b - или если оно имеет только ограничение для a (но not , если это только проверка против б).

Кроме того, это некластеризованный индекс на столбец так же, как некластеризованный индекс по а, с?

Нет, это не так - но оптимизатор запросов SQL Server будет использовать этот некластеризованный индекс, если он встретит запрос с предложением WHERE только на "a".

Марк

2 голосов
/ 16 сентября 2009

индекс A, B отличается от индекса B, A

Это потому, что индекс организован в определенном порядке сортировки. Итак, представьте, что вам нужно выполнить поиск с помощью следующего предложения WHERE

WHERE A='somecrit' AND B='SomepartialCrit%'  -- notice the wildcard

Индекс A, B будет очень эффективен при разрешении запроса, но если бы он был

WHERE   A='SomepartialCrit%'  AND B='somecrit'

Индекс (A, B) только частично поможет (может быть лучше, чем полное сканирование таблицы, но не оптимально), в результате чего индекс (B, A) придет на помощь ...

Для использования с запросом, который включает в себя как А, так и В в качестве точного соответствия (без подстановочных знаков), любой индекс может использоваться эквивалентным образом (с точки зрения эффективности), хотя выбор одного конкретного индекса может быть обусловлен другой частью запроса, такого как предложения ORDER BY и т. д.

Индекс на A отличается от индекса на A, C Для одного индекс на A, C может использоваться для разрешения запросов, которые включают критерии и A, и C, а также индекс A, C может использоваться для «покрытия» предложения SELECT или его части, то есть: если предложение SELECT включает только столбцы A и C (из этой конкретной таблицы), SQL может предоставить результаты без необходимости получать данные из самой таблицы, он получит значения A и C из одного индекса.

Являются ли "избыточные" индексы плохой вещью?

Как сказано выше, дополнительные индексы могут помочь более эффективно разрешать запросы SELECT. С другой стороны, они а) используют пространство хранения и б) делают запросы INSERT, UPDATE и DELETE менее эффективными (поскольку новые / обновленные / удаленные значения необходимо добавлять / изменять / удалять в большем количестве мест.

Поэтому необходимо найти правильный баланс на основе доступного доступного пространства хранения и варианта использования (некоторые базы данных, в основном доступные только для чтения, могут иметь множество индексов без ущерба для производительности, базы данных с частыми вставками могут видеть их производительность сильно ухудшается при слишком большом количестве индексов)

По кластеризованным индексам

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...