Могут ли несколько индексов работать вместе? - PullRequest
14 голосов
/ 29 сентября 2008

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

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

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

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

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

Ответы [ 9 ]

11 голосов
/ 29 сентября 2008

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

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

Одним из важных соображений здесь может быть любая корреляция между запрашиваемыми значениями. Если foo = 'hello' составляет 80% значений в таблице, а bar = 'world' - 10%, то Oracle рассчитывает, что запрос вернет 0,8 * 0,1 = 8% строк таблицы. Однако это может быть неверно - запрос может фактически вернуть 10% строк или даже 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)
/
3 голосов
/ 07 октября 2008

Eli

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

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

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

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

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

3 голосов
/ 29 сентября 2008

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

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

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

CREATE INDEX IX_BAR_AND_FOO on sometable(bar,foo);

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

2 голосов
/ 29 сентября 2008

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

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

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

2 голосов
/ 29 сентября 2008

Значит, Oracle достаточно умен, чтобы искать эффективно здесь?

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

1 голос
/ 29 сентября 2008

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

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

1 голос
/ 29 сентября 2008

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

1 голос
/ 29 сентября 2008

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

1 голос
/ 29 сентября 2008

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

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