Вы должны искать каждое условие where и каждое соединение... при условии. Оба работают одинаково.
Предположим, мы пишем
select name
from customer
where customerid=37;
Каким-то образом СУБД должна найти запись или записи с идентификатором клиента=37. Если индекса нет, единственный способ сделать это — прочитать каждую запись в таблице, сравнивая идентификатор клиента с 37. Даже когда он находит один, он не может знать, что он только один, поэтому он должен продолжать поиск. другие.
Если вы создаете индекс по идентификатору клиента, у СУБД есть способы очень быстрого поиска по индексу. Это не последовательный поиск, а, в зависимости от базы данных, бинарный поиск или какой-либо другой эффективный метод. Как именно, не имеет значения, примите во внимание, что это намного быстрее, чем последовательное. Затем индекс переносит его непосредственно к соответствующей записи или записям. Кроме того, если вы укажете, что индекс является «уникальным», то база данных знает, что может быть только один, поэтому она не тратит время на поиски второго. (И СУБД не позволит вам добавить второй.)
Теперь рассмотрим этот запрос:
select name
from customer
where city='Albany' and state='NY';
Теперь у нас есть два условия. Если у вас есть индекс только для одного из этих полей, СУБД будет использовать этот индекс для поиска подмножества записей, а затем последовательно искать их. Например, если у вас есть индекс по штату, СУБД быстро найдет первую запись для NY, затем последовательно ищет city='Albany' и прекратит поиск, когда дойдет до последней записи для NY.
Если у вас есть индекс, который включает оба поля, т.е. «создать индекс по клиенту (штат, город)», то СУБД может сразу перейти к нужным записям.
Если у вас есть два отдельных индекса, по одному для каждого поля, СУБД будет иметь различные правила, которые она применяет, чтобы решить, какой индекс использовать. Опять же, как именно это делается, зависит от конкретной используемой СУБД, но в основном она пытается вести статистику по общему количеству записей, количеству различных значений и распределению значений. Затем он будет последовательно искать в этих записях те, которые удовлетворяют другому условию. В этом случае СУБД, вероятно, обнаружит, что городов гораздо больше, чем штатов, поэтому, используя индекс города, она может быстро приблизиться к записям «Олбани». Затем он будет последовательно искать их, проверяя состояние каждого на соответствие «NY». Если у вас есть записи для Олбани, Калифорния, они будут пропущены.
Каждое соединение требует некоторого поиска.
Скажем, мы пишем
select customer.name
from transaction
join customer on transaction.customerid=customer.customerid
where transaction.transactiondate='2010-07-04' and customer.type='Q';
Теперь СУБД должна решить, какую таблицу читать первой, выбрать оттуда соответствующие записи, а затем найти совпадающие записи в другой таблице.
Если бы у вас был индекс для transaction.transactiondate и customer.customerid, лучшим планом, вероятно, было бы найти все транзакции с этой датой, а затем для каждой из них найти клиента с соответствующим идентификатором клиента, а затем убедиться, что клиент правильный тип.
Если у вас нет индекса для customer.customerid, СУБД могла бы быстро найти транзакцию, но тогда для каждой транзакции ей пришлось бы последовательно искать в таблице клиентов соответствующий идентификатор клиента. (Вероятно, это будет очень медленно.)
Вместо этого предположим, что у вас есть только индексы transaction.customerid и customer.type. Тогда СУБД, скорее всего, будет использовать совершенно другой план. Вероятно, он будет сканировать таблицу клиентов на наличие всех клиентов с правильным типом, затем для каждого из них находить все транзакции для этого клиента и последовательно искать в них нужную дату.
Самый важный ключ к оптимизации — выяснить, какие индексы действительно помогут, и создать эти индексы. Дополнительные, неиспользуемые индексы являются бременем для базы данных, поскольку для их обслуживания требуется работа, и если они никогда не используются, это напрасная трата усилий.
Вы можете указать, какие индексы СУБД будет использовать для любого заданного запроса, с помощью команды EXPLAIN. Я использую это все время, чтобы определить, хорошо ли оптимизируются мои запросы или мне следует создавать дополнительные индексы. (Прочитайте документацию по этой команде для объяснения ее вывода.)
Предостережение: помните, я сказал, что СУБД хранит статистику по количеству записей и количеству различных значений и так далее в каждой таблице. EXPLAIN может дать вам сегодня совершенно другой план, чем вчера, если данные изменились. Например, если у вас есть запрос, который соединяет две таблицы, и одна из этих таблиц очень маленькая, а другая большая, он будет смещен в сторону чтения сначала маленькой таблицы, а затем поиска совпадающих записей в большой таблице. Добавление записей в таблицу может измениться, что больше, и, таким образом, привести к изменению плана СУБД. Таким образом, вы должны попытаться выполнить EXPLAINS для базы данных с реалистичными данными. Работа с тестовой базой данных с 5 записями в каждой таблице имеет гораздо меньшую ценность, чем работа с действующей базой данных.
Что ж, можно еще много чего сказать, но я не хочу писать здесь книгу.
person
Jay
schedule
07.07.2010