Задать вопрос
nelauvetau
@nelauvetau

Оптимизация запроса mysql — exists vs in?

Есть два запроса - один с EXISTS, второй с IN.

SELECT bl.id
FROM book_list bl
WHERE bl.active=1
AND EXISTS (SELECT id_book FROM book_codes bc WHERE bc.id_book = bl.id and bc.code LIKE '%f1%')
ORDER BY bl.id desc;

SELECT bl.id
FROM book_list bl
WHERE bl.active=1
AND bl.id in (SELECT id_book FROM book_codes bc WHERE bc.id_book = bl.id and bc.code LIKE '%f1%')
ORDER BY bl.id desc;

Не могу понять, почему первый запрос эффективнее, когда в строке для поиска через LIKE один символ, но чем больше символов я ищу через LIKE, тем первый запрос медленнее.
Второй запрос всегда отрабатывает приблизительно за одно и то же время.

Неважно, какой размер строки для поиска через LIKE, первый запрос по explain перебирает в book_codes порядка 10тыс записей, а второй - порядка 4мл по одному и тому же ключу id_book.
В book_codes > 4млн записей.

UPD:
Изначально я написала запрос через JOIN
SELECT bl.id
FROM book_list bl
JOIN book_codes bc on bc.id_book = bl.id 
WHERE bl.active=1 AND bc.code LIKE '%ww%'
GROUP BY bl.id
ORDER BY bl.id desc;


Но на кодревью JOIN завернули и предложили
AND bl.id in (SELECT id_book FROM book_codes bc WHERE bc.id_book = bl.id and bc.code LIKE '%f1%')


Explain всех трех запросов
5d9b72cf02db9497322298.png

UPD UPD
По полю bс.code тоже есть индекс
  • Вопрос задан
  • 527 просмотров
Подписаться 1 Средний 15 комментариев
Пригласить эксперта
Ответы на вопрос 3
@ghostiam
На Go писатель, серверов пинатель.
Мне кажется, вы не верно используете EXIST и из за этого не верно выполняется запрос.
А зачем здесь собственно IN/EXIST, кажется этот же запрос будет более эффективен, если использовать JOIN.
SELECT bl.id
FROM book_list bl
JOIN book_codes bc ON bc.id_book = bl.id
WHERE bl.active=1
AND bc.code LIKE '%f1%'
ORDER BY bl.id desc;
Ответ написан
Комментировать
VladimirAndreev
@VladimirAndreev
php web dev
А зачем подзапрос?
Не будет быстрее сделать inner join book_codes, а в where добавить проверку кода?
Ответ написан
Комментировать
dimonchik2013
@dimonchik2013
non progredi est regredi
в первом еиу достаточно пройти
SELECT code FROM book_codes where code LIKE '%f1%'
и при TRUE выполить остальные XOR: bc.id_book = bl.id, bl.active=1 что практически мгновенно, пока не будет найден первый TRUE для EXISTS

во втором же приходится создавать массив id_book & bc.code ( он и создает его на все 4млн что есть), а затем прогонять по нему bl.id
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы