#mysql #sql
Подскажите пожалуйста: если в запросе несколько условий, например, WHERE a=1 AND b=2, то сначала выбираются данные, удовлетворяющие условию a=1, а потом среди них выбираются данные по условию b=2? Или для второго условия поиск идет опять по всей таблице? Целесообразен, конечно, первый вариант, но что-то нигде не нашел явного подтверждения.
Ответы
Ответ 1
Зависит от индексов и изобретательности оптимизатора. Ну и надо понимать, что разработчики базы, как правило, достаточно опытные люди. Проверить всё это можно, запустив EXPLAIN вашего запроса. Если индексов на эти поля нет ...то надо принять решение: делать по две проверки в одном проходе или два прохода по одной проверке. Если данные целиком помещаются в кэше процессора (почти нереальный случай), то разница заметна не будет. Если не помещаются, то в кэш будут последовательно загружаться разные участки проверяемого набора данных из оперативной памяти (если набор данных туда помещается). Загрузка в кэш занимает какое-то микровремя, но оно становится тем больше, чем больше таблица. Делать два прохода выходит уже дороже: на прежний объём сравнений нужно сделать вдвое больше загрузок в кэш. Если данные не помещаются даже в оперативную память, всё совсем очевидно — загрузка с диска очень долгая. Настолько, что остальные части запроса вряд ли будут заметны, и выполнение двух обходов, скорее всего, примерно вдвое увеличит время выполнения запроса. Итог: обход один, две проверки на каждый ряд выглядят рациональнее со всех сторон. Если есть индекс на одном из полей ...то всё очевидно: сходу есть возможность "дёшево" (по ресурсам) сократить перебираемый набор данных до части таблицы с заданным значением в проиндексированном поле. А уже по этому набору выполнить последовательный перебор и проверить второе условие. Если есть индексы на двух полях ...то фиг EXPLAIN его знает! Более достоверного ответа никто не даст, каждая БД решает этот вопрос как-то по-своему. Оптимизатор может посмотреть в оба индекса, прикинуть где последовательный перебор окажется меньше и использовать его. А может ошибиться и взять не тот, руководствуясь какими-то своими соображениями. PostgreSQL умеет делать bitmap scan, в ходе которого он сканирует оба индекса и составляет карту (bitmap) по каждому условию, а затем объединяет две карты в одну согласно условиям, получая результат. Но делать ли это, решает оптимизатор. В идеале: если есть индекс по парам значений Здесь индекс просто используется напрямую, поэтому порядок поиска будет совпадать с порядком индексирования: сначала спуск с "верхних уровней индекса" (по первому выражению), а затем спуск по второму и сразу получает ответ. Но всё это неважно, если... данных совсем мало небольшие объёмы данных может быть быстрее обойти без индекса оптимизатор облажается (что бывает) отладка чего превращается в охоту за индексами путём чтения EXPLAINовОтвет 2
Дополню ещё про "бывает всякое". Была ситуация с SQL Server, но это даже не принципиально -- думаю, похожая ситуация может быть и с другими СУБД. Запрос вида (сильно упрощено, в реальности конечно страницы на две): SELECT CONVERT(fielda, INT) FROM tablea WHERE ... Поле fielda здесь было текстовым, но условием WHERE гарантированно отрезались все невалидные значения (т.е. такие которые нельзя было преобразовать в INT). И запрос периодически падал на CONVERT. Ручная проверка ничего не давала -- выборкой по данному условию было видно, что выбираются валидные значения, и CONVERT работает. Но тут дело уже в том как сервер БД решает выполнить запрос. Он может взять блок данных и сначала выполнить CONVERT, а уже потом отрезать лишние строки.Ответ 3
БД выполняет запрос не дословно, на основе запроса составляется план выполнения (query plan), на который будет влиять например наличие индексов. Посмотреть что там в реальности отработает можно через EXPLAIN перед запросом, но его результат еще тоже надо уметь прочитать. На план выполнения можно повлиять в плане джоинов и индексов (FORCE INDEX), но это не полный контроль, в целом оптимизатор БД призван сам решать такие вопросы.
Комментариев нет:
Отправить комментарий