Я читал о, composite indexes
и я немного запутался по поводу заказа. Эта документация (чуть менее половины пути) говорит
В общем, вы должны поместить столбец, который, как ожидается, будет использоваться наиболее часто, первым в индексе.
Однако вскоре после этого говорится
создайте составной индекс, поместив наиболее селективный столбец первым; то есть столбец с наибольшим количеством значений.
Oracle также говорит это здесь другими словами
Если все ключи используются в предложениях WHERE одинаково часто, то упорядочение этих ключей от наиболее избирательных к наименее селективным в операторе CREATE INDEX лучше всего повышает производительность запросов.
Тем не менее, я нашел SO ответ, который говорит по-другому. Это говорит
Расположите столбцы с наименее селективным столбцом первым и наиболее избирательным столбцом последним. В случае связующего провода с колонкой, которая, скорее всего, будет использоваться самостоятельно.
Первая документация, на которую я ссылался, гласит, что вы должны сначала перейти на наиболее часто используемые, тогда как ответ SO говорит, что это должно быть только для разрыва связи. Тогда они также различаются по порядку.
Эта документация также говорит skip scanning
и говорит
Пропускное сканирование выгодно, если в начальном столбце составного индекса имеется несколько отдельных значений и много значений в неконечном ключе индекса.
Другая статья говорит
Столбец префикса должен быть наиболее разборчивым и наиболее широко используемым в запросах.
который я считаю наиболее различительным будет означать наиболее характерным.
Все эти исследования все еще приводят меня к одному и тому же вопросу; Должен ли самый селективный столбец быть первым или последним? Должен ли первый столбец быть наиболее используемым и только самым избирательным на тай-брейке?
Эти статьи, кажется, противоречат друг другу, но они предлагают некоторые примеры. Из того, что я понял, кажется, что более эффективно least selective column
быть первым в заказе, если вы ожидаете Index Skip Scans
. Но я не совсем уверен, правильно ли это.
источник
Ответы:
От AskTom
Один из аргументов для размещения столбцов в составном индексе по порядку от наименее различающих (менее различимых значений) до наиболее различающих (более отчетливых значений) относится к сжатию ключа индекса.
Согласно статистике индекса, первый индекс является более сжимаемым.
Другое - как индекс используется в ваших запросах. Если ваши запросы в основном используют
col1
,Например, если у вас есть вопросы вроде
select * from t where col1 = :a and col2 = :b;
select * from t where col1 = :a;
- тогда
index(col1,col2)
будет лучше.Если ваши запросы в основном используют
col2
,select * from t where col1 = :a and col2 = :b;
select * from t where col2 = :b;
- тогда
index(col2,col1)
будет лучше. Если во всех ваших запросах всегда указываются оба столбца, то не имеет значения, какой столбец стоит первым в составном индексе.В заключение следует отметить, что основными соображениями при упорядочении столбцов составного индекса являются сжатие ключа индекса и то, как вы собираетесь использовать этот индекс в своих запросах.
Ссылки:
источник
Первый выбор наиболее полезен, только если этот столбец находится в фактическом предложении WHERE.
Когда SELECT относится к большей группе (менее избирательной), а затем, возможно, по другим неиндексированным значениям, индекс с менее селективными столбцами может все еще быть полезным (если есть причина не создавать другой).
Если есть таблица АДРЕС, с
УЛИЦА ГОРОДА СТРАНЫ, что-то еще ...
Индексирование STREET, CITY, COUNTRY даст самые быстрые запросы с названием улицы. Но при запросе всех улиц города индекс будет бесполезным, и запрос, скорее всего, произведет полное сканирование таблицы.
Индексирование COUNTRY, CITY, STREET может быть немного медленнее для отдельных улиц, но индекс можно использовать для других запросов, выбирая только по стране и / или городу.
источник
При выборе порядка столбцов индекса важнее всего:
Есть ли в моих запросах (равенство) предикаты против этого столбца?
Если столбец никогда не появляется в предложении where, индексировать его не стоит (1)
Итак, у вас есть таблица и запросы к каждому столбцу. Иногда больше, чем один.
Как вы решаете, что индексировать?
Давайте посмотрим на пример. Вот таблица с тремя столбцами. Один содержит 10 значений, другой 1000, последние 10 000:
Это числа, заполненные нулями. Это поможет сделать вывод о сжатии позже.
Итак, у вас есть три общих запроса:
Что вы индексируете?
Индекс только на times_val только немного лучше, чем полное сканирование таблицы:
Так что вряд ли стоит индексировать самостоятельно. Запросы на lots_vals возвращают несколько строк (в данном случае только 1). Так что это определенно стоит индексировать.
Но как насчет запросов к обоим столбцам?
Если вы индексировать:
ИЛИ
Хитрый вопрос!
Ответ ни один.
Конечно, little_vals - это длинная строка. Таким образом, вы можете получить хорошее сжатие из этого. И вы (возможно) получите сканирование с пропуском индекса для запросов с использованием (many_vals, lots_vals), которые имеют предикаты только для lots_vals. Но я не здесь, хотя он работает заметно лучше, чем полное сканирование:
Вам нравится играть в азартные игры? (2)
Таким образом, вам все еще нужен индекс с lots_vals в качестве ведущего столбца. И, по крайней мере, в этом случае составной индекс (несколько лотов) выполняет ту же работу, что и индекс «просто» (лоты).
Будут случаи, когда составной индекс экономит вам 1-2 IO. Но стоит ли иметь два индекса для этой экономии?
И есть еще одна проблема с составным индексом. Сравните коэффициент кластеризации для трех индексов, включая LOTS_VALS:
Обратите внимание, что коэффициент кластеризации для two_lots в 10 раз выше, чем для лотов и lots_few! И это в демонстрационной таблице с идеальной кластеризацией для начала. В реальных базах данных эффект, вероятно, будет хуже.
Так что в этом плохого?
Фактор кластеризации является одним из ключевых факторов, определяющих, насколько «привлекательным» является индекс. Чем оно выше, тем меньше вероятность, что оптимизатор выберет его. Особенно, если lots_vals на самом деле не уникален, но все же обычно имеет несколько строк на значение. Если вам не повезло, этого может быть достаточно, чтобы оптимизатор решил, что полное сканирование дешевле ...
Хорошо, поэтому составные индексы с less_vals и lots_vals имеют преимущества только в крайнем случае.
Как насчет запросов, фильтрующих little_vals и many_vals?
Индексы с одним столбцом дают только небольшие преимущества. Но вместе они возвращают мало значений. Так что составной индекс - это хорошая идея. Но в какую сторону?
Если вы поместите несколько первых, сжатие ведущей колонки сделает это меньше
С меньшим количеством разных значений в ведущем столбце сжимается лучше. Таким образом, есть немного меньше работы, чтобы прочитать этот индекс. Но только немного. И то, и другое уже хороший кусок меньше, чем оригинал (уменьшение на 25%).
И вы можете пойти дальше и сжать весь индекс!
Теперь оба индекса вернулись к одному и тому же размеру. Обратите внимание, что это использует тот факт, что есть отношения между немногими и многими. Опять же, вряд ли вы увидите такую выгоду в реальном мире.
До сих пор мы говорили только о проверках равенства. Часто с составными индексами вы получите неравенство с одним из столбцов. например, такие запросы, как «получить заказы / отгрузки / счета для клиента за последние N дней».
Если у вас есть такие запросы, вам нужно равенство с первым столбцом индекса:
Обратите внимание, что они используют противоположный индекс.
TL; DR
1: В некоторых случаях может быть целесообразно включить столбец в индекс, если это означает, что все столбцы в вашем запросе находятся в индексе. Это позволяет сканировать только по индексу, поэтому вам не нужно обращаться к таблице.
2. Если у вас есть лицензия на диагностику и настройку, вы можете принудительно пропустить план с помощью SQL Plan Management
ADDEDNDA
PS - документы, которые вы цитировали, есть от 9i. Это очень старое. Я бы придерживался чего-то более недавнего
источник
select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
действительно распространенным? Разве Oracle не допускает синтаксисselect count (distinct few_vals, many_vals, lots_vals )
- который не выполняет конкатенацию строк, не нуждается в столбцах для текстовых типов и не использует отсутствие:
символа?count ( distinct x, y, z )
в Oracle. Таким образом, вам нужно сделать отдельный подзапрос и подсчитать результаты или конкатенацию, как указано выше. Я просто сделал это здесь для принудительного доступа к таблице (а не для сканирования только по индексу) и просто получил одну строку в результатеБольше элементов запроса вносит свой вклад в окончательное решение о том, что должен начинаться с составного индекса и / или содержать помимо селективности столбца.
например:
">,> =, <, <="
Тем не менее, чтобы поддержать разговор, мой следующий ответ относится к следующей ситуации:
строка»
По моему опыту, администратор БД должен помнить об этом.
1) Если я создаю индекс с наиболее селективным столбцом, являющимся первым, но этот столбец фактически не используется большинством запросов к этой таблице, он не используется для механизма обработки БД.
2) Если я создаю индекс с наиболее широко используемым столбцом в запросе, который является первым в индексе, но столбец имеет низкую селективность, то и производительность моего запроса не будет хорошей.
Я перечислю столбцы, которые в основном используются в 90% запросов к таблице. Затем поместите их только в порядке наибольшего количества элементов к наименьшему количеству элементов.
Мы используем индексы для повышения производительности запросов на чтение, и этот рабочий процесс (типы запросов на чтение) только должен управлять созданием индекса. Фактически, когда данные растут (миллиарды строк), сжатый индекс может сэкономить хранилище, но, безусловно, снизит производительность запроса на чтение.
источник
Теоретически наиболее селективный столбец дает самый быстрый поиск. Но на работе я просто наткнулся на ситуацию, когда у нас составной индекс из 3 частей, причем сначала наиболее селективная часть. (дата, автор, издательская компания, скажем, в таком порядке, таблица следит за публикациями), и у меня есть запрос, который использует все 3 части. Mysql по умолчанию использует только авторский индекс, пропуская составной индекс, содержащий компанию и дату, несмотря на то, что они присутствуют в моем запросе. Я использовал Force Index, чтобы использовать композит, и запрос на самом деле работал медленнее. Почему это случилось? Я скажу вам:
Я выбирал диапазон для даты, поэтому, несмотря на то, что дата является очень избирательной, тот факт, что мы используем ее для сканирования диапазона (даже если диапазон относительно короткий, 6 месяцев из 6 лет данных), сделал составной вредным для MySQL. Чтобы использовать композит в этом конкретном случае, mysql должен взять все статьи, написанные с нового года, а затем погрузиться в то, кто автор, и, учитывая, что автор не написал так много статей по сравнению с другими авторами, mysql предпочел просто найти этого автора. ,
В другом случае запрос выполнялся намного быстрее в композите, когда автор был чрезвычайно популярен и владел большинством записей, сортировка по дате имела смысл. Но MySQL не обнаружил этот случай автоматически, мне пришлось форсировать индекс ... Так что вы знаете, он меняется. Сканирование диапазона может сделать вашу выборочную колонку бесполезной. Распределение данных может привести к тому, что столбцы будут более избирательными для разных записей ...
То, что я бы сделал по-другому, - это сдвинул дату (которая опять-таки, теоретически, является наиболее избирательной) вправо, поскольку я знаю, что сейчас буду выполнять сканирование диапазона, и это имеет значение.
источник
WHERE (date BETWEEN @x AND @y) AND (author = @a) AND (publishing company = @p)
тогда индекс(author, publishing_company, date)
или(publishing_company, author, date)
будет лучше и будет использоваться - не заставляя его.Разные случаи для разных ситуаций. Знай свою цель; затем создайте свои индексы и выполните планы объяснения для каждого из них, и у вас будет лучший ответ для вашей ситуации.
источник
Из порядка столбцов в указателе на вопрос Тома:
Согласитесь, что мы должны упорядочивать столбцы, основываясь на предложении where, но утверждение «(селективность a или b не учитывается вообще)» неверно.) «. Наиболее избирательные столбцы должны быть ведущими, если удовлетворена первая роль ("где пункт")
источник