Может ли несколько индексов работать вместе?

Предположим, что у меня есть таблица базы данных с двумя полями: "foo" и "bar". Ни один из них не является уникальным, но каждый из них индексируется. Однако, вместо того, чтобы индексироваться вместе, каждый из них имеет отдельный индекс.

Теперь предположим, что я выполняю такой запрос, как SELECT * FROM sometable WHERE foo='hello' AND bar='world'; My table, огромное количество строк, для которых foo является "hello" , и небольшое количество строк, для которых bar является "миром" .

Таким образом, самая эффективная вещь для сервера базы данных, выполняемая под капотом, - это использовать индекс бара, чтобы найти все поля, где bar является "миром" , а затем возвращать только те строки, для которых foo является "hello" . Это O(n), где n - количество строк, где bar является "миром" .

Однако, я думаю, возможно, что процесс произойдёт в обратном порядке, где используется индекс fo и результаты поиска. Это будет O(m), где m - количество строк, где foo - "hello" .

Итак, Oracle достаточно умна, чтобы эффективно искать здесь? Как насчет других баз данных? Или я могу сказать это в своем запросе для поиска в правильном порядке? Возможно, сначала положив bar='world' в предложение WHERE?

Ответы

Ответ 1

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

Кроме того, Oracle может сочетать использование обоих индексов несколькими способами - он может преобразовывать индексы btree в растровые изображения и выполнять на них растровую ANd-операцию или может выполнять хеш-соединение на rowid, возвращаемом двумя индексов.

Одним из важных соображений здесь может быть любая корреляция между запрашиваемыми значениями. Если foo = 'hello' учитывает 80% значений в таблице, а bar = 'world' - 10%, то Oracle собирается оценить, что запрос вернет 0.8 * 0.1 = 8% строк таблицы. Однако это может быть неверным - запрос может фактически вернуть 10% от rwos или даже 0% строк в зависимости от того, насколько коррелированы значения. Теперь, в зависимости от распределения этих строк по всей таблице, может оказаться неэффективным использовать индекс для их поиска. Вам все равно может потребоваться (скажем) 70% или табличные блоки для получения требуемых строк (google для "фактора кластеризации" ), и в этом случае Oracle собирается выполнить проверку полной таблицы, если она правильно оценивает.

В 11g вы можете собирать многоколоночную статистику, чтобы помочь в этой ситуации, я верю. В 9i и 10g вы можете использовать динамическую выборку, чтобы получить очень хорошую оценку количества возвращаемых строк.

Чтобы получить план выполнения, выполните следующие действия:

explain plan for
SELECT *
FROM   sometable
WHERE  foo='hello' AND bar='world'
/
select * from table(dbms_xplan.display)
/

Контрастность:

explain plan for
SELECT /*+ dynamic_sampling(4) */
       *
FROM   sometable
WHERE  foo='hello' AND bar='world'
/
select * from table(dbms_xplan.display)
/

Ответ 2

Да, вы можете дать "подсказки" с запросом к Oracle. Эти подсказки замаскированы как комментарии ( "/* HINT */" ) в базу данных и в основном зависят от поставщика. Таким образом, одна подсказка для одной базы данных не будет работать в другой базе данных.

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

С другой стороны, если вы часто просматриваете эти два поля, почему бы не создать индекс для этих двух? У меня нет правильного синтаксиса, но это будет что-то вроде

CREATE INDEX IX_BAR_AND_FOO on sometable(bar,foo);

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

Ответ 3

Эли,

В комментарии вы писали:

К сожалению, у меня есть таблица с большим количеством столбцов, каждая со своим индексом. Пользователи могут запрашивать любую комбинацию полей, поэтому я не могу эффективно создавать индексы для каждой комбинации полей. Но если бы у меня было только два поля, требующие индексов, я бы полностью согласился с вашим предложением использовать два индекса. - Eli Courtwright (29 сентября в 15:51)

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

Этот сценарий именно поэтому были изобретены растровые индексы - для обработки времен, когда неизвестные группы столбцов будут использоваться в предложении where.

На всякий случай кто-то скажет, что ИМТ предназначены только для столбцов с низкой мощностью и могут не применяться к вашему делу. Низкий, вероятно, не такой маленький, как вы думаете. Единственная реальная проблема - concurrency DML в таблице. Для этого нужно быть однопоточным или редким.

Ответ 4

Итак, Oracle достаточно умна для поиска здесь эффективно?

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

Ответ 5

Во-первых, я предполагаю, что вы говорите о хороших нормальных стандартных индексах b * -tree. Ответ на битмап-индексы радикально отличается. И есть много вариантов для различных типов индексов в Oracle, которые могут или не могут изменить ответ.

Как минимум, если оптимизатор может определить селективность конкретного условия, он будет использовать более избирательный индекс (т.е. индекс на баре). Но если у вас есть перекошенные данные (в столбце есть N значений, но избирательность любого конкретного значения существенно больше или меньше 1/N данных), вам нужно будет иметь гистограмму в столбце, чтобы сообщить оптимизатор, значения которого более или менее вероятны. И если вы используете переменные связывания (как и все хорошие разработчики OLTP), в зависимости от версии Oracle у вас могут возникнуть проблемы с зависанием переменных.

Потенциально Oracle может даже сделать преобразование двух индексов b * -tree в растровые изображения и комбинировать растровые изображения, чтобы использовать оба индекса для поиска строк, которые ему нужно получить. Но это довольно необычный план запроса, особенно если есть только два столбца, где один столбец является высокоселективным.

Ответ 6

Я уверен, что вы также можете отобразить Oracle план запроса, чтобы вы могли точно видеть, какой индекс используется первым.

Ответ 7

Вы можете указать, какой индекс использовать. Я не знаком с Oracle, но в Mysql вы можете использовать USE | IGNORE | FORCE_INDEX (см. здесь для получения дополнительной информации). Для лучшей производительности, хотя вы должны использовать комбинированный индекс.

Ответ 8

Лучшим подходом было бы добавить foo в индекс bar или добавить bar в индекс foo (или оба). Если индекс foo также содержит индекс на баре, этот дополнительный уровень индексации не будет влиять на полезность индекса foo в любом текущем использовании этого индекса и не будет заметно влиять на производительность поддержания этого индекса, но он даст дополнительную базу данных информацию для работы с оптимизацией запросов, например, в этом примере.

Ответ 9

Это лучше, чем это.

Поиск индексов всегда быстрее, чем полное сканирование таблицы. Поэтому за кулисами Oracle (и SQL-сервер, если на то пошло) сначала найдет диапазон строк по обоим индексам. Затем он посмотрит, какой диапазон короче (видя, что это внутреннее соединение), и он будет итерировать более короткий диапазон, чтобы найти совпадения с большим из двух.