2013-10-28 2 views
0

Я изучаю, как делать правильную оптимизацию запросов с использованием индексов. Предположим, у меня есть огромная таблица продуктов со всеми видами деталей для каждого продукта, например. цена, категория, количество покупок, средний показатель обзора и т. д. При наличии нескольких условий «где» я узнал, что лучше всего разместить индекс с несколькими столбцами во всех ваших условиях «где», в том порядке, в котором они появляются.Как оптимизировать запросы с пользовательскими параметрами в предложении «где»?

Однако мне сложно понять, как масштабировать его, если есть так много запросов для разных целей, и если пользователи получат возможность выбирать, как фильтровать таблицу продуктов. Например, пользователь может просматривать продукты WHERE rating > 4 AND purchases > 100, или это может быть WHERE category = 'x' AND price < 100 AND price > 20. Как работает правильный многоколоночный индекс, если выбранные столбцы для фильтрации являются случайными?

ответ

1

Я узнал, что лучше всего поставить индекс с несколькими столбцами на все ваши условия «где», в том порядке, в котором они появляются.

Вы узнали ... не совсем правильно.

Порядок появления в пункте WHERE не имеет смысла, так как оптимизатор волен оценивать условия в любом логически действительным образом, при условии, конечно, круглых скобок и логических операторов (AND, OR и т.д.) в выражении ,

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

Если индексируются 3 столбца (a, b, c), а запрос равен WHERE a = 1 AND c = 6, тогда оптимизатор сможет использовать только самые левые значения столбца «a» в этом индексе, а не «c».

В этом случае, скорее всего, по-прежнему предпочитает использовать индекс, чтобы найти строки, где а = 1, а затем сканировать все выявленные строки только для тех, с = 6.

Вы можете визуализировать мульти -колонный индекс как многомерный массив. Без известного значения или диапазона вам нужно совпадение для первого столбца (a), значения для второго столбца (b) являются бессмысленным беспорядочным беспорядком данных, поскольку они сортируются в «группах» a. .. вам нужно будет перебирать все «а», чтобы найти соответствующие значения «b», и перебирать все «a, b», чтобы найти соответствующие значения «c». Так как в приведенном выше примере значение «b» «ничего», поскольку оно не указано, упорядочение значений «c» бессмысленно и недоступно для оптимизации запроса (хотя, когда каждый столбец в списке SELECT доступен в одном индексе оптимизатор может сканировать индекс вместо сканирования всей таблицы, рассматривая его как «индекс покрытия», который обычно лучше, чем полное сканирование таблицы, но все еще субоптимально).

Если ваш пункт WHERE содержит два столбца, оба из которых индексируются индивидуально, оптимизатор проверяет статистику индекса и пытается использовать ту, которая, скорее всего, будет производить наименьшее количество совпадений ... если «a» и «c «каждый из них имеет индивидуальный индекс, а статистика индекса указывает, что существует множество значений для« c »(высокая мощность), но только несколько значений для« a »(малая мощность), оптимизатор обычно будет использовать индекс на« c »до найдите соответствующие строки, затем сканируйте все эти строки для запрошенных значений «a».

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

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

В случае WHERE category = 'x' AND price < 100 AND price > 20 лучшим индексом будет (категория, цена) и нет (цена, категория), но это не из-за упорядочения выражений в предложении WHERE. Это потому, что категория - это тест равенства, но цена - это диапазон. WHERE price < 100 AND price > 20 AND category ='x' эквивалентен, и (категория, цена) по-прежнему является соответствующим индексом - поскольку индексы сортируются по первому столбцу, то в каждом значении для первого столбца они сортируются по значениям второго столбца, а затем внутри каждого (первая, вторая), они сортируются по значениям в третьем столбце, ad infinitum ... так что (категория, цена) сервер переходит непосредственно ко всем строкам для категории = 'x' и внутри этой группировки в индекс, ссылочные строки уже отсортированы по цене, поэтому ему нужно только выбрать диапазон цены в категории «х» индекса. Оптимальное. Индекс (цена, категория) требует проверки всех цен в диапазоне, а затем обжатия значения категории для всех из них. Индекс все еще можно использовать, но в зависимости от критериев оптимизатор все же может выбрать сканирование всей таблицы.

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

Для каждого индекса требуется пространство и ресурсы, поскольку для каждой вставки, обновления и удаления требуется, чтобы сервер внес необходимые изменения - прямо в каждый индекс, на который влияют изменения в таблице. Обратите внимание также, что если у вас есть индекс на (a, b) или (a, b, c) и т. Д., То отдельный индекс на (a) обычно считается пустой тратой пространства, поскольку индекс на (a, ... anything-else ...) также будет служить индексом на (a).

Экспериментирование с EXPLAIN SELECT (который также поддерживает INSERT/UPDATE/DELETE по состоянию на MySQL 5.6) и действительно understanding its output является незаменимым инструментом для понимания того, как работают индексы. MySQL 5.6 также поддерживает optimizer tracing, что дает подробный вывод о том, как оптимизатор понял ваш запрос, различные планы, которые он рассмотрел, стоимость, которую он оценил по каждому плану, и как он пришел к решению о том, как выполнить конкретный запрос.

+0

спасибо, что объяснили. Я должен признать, что некоторые из них все еще над моей головой. Мне нужно будет прочитать выходную страницу EXPLAIN, когда у меня есть время, и посмотрите главу оптимизации в книге MySQL. Еще раз спасибо. –

+0

Спасибо. Пожалуйста, подумайте о том, чтобы принять ответ или сообщить мне, есть ли пункты, которые я могу уточнить. –

Смежные вопросы