MySQL и Inline выбирают
Вопрос
У меня есть запрос, который выглядит так:
select
id
, int1
, int2
, (select count(*) from big_table_with_millions_of_rows
where id between t.int1 and t.int2)
from myTable t
where
....
Этот выбор возвращает ровно одну строку. Идентификатор, используемый в встроенном выборе, является индексированным столбцом (первичный ключ). Если я заменю t.int1
а также t.int2
С значениями Int1/Int2, возвращенными этой единственной строкой, запрос завершается в миллисекундах. Если я выполняю запрос, как указано выше - т.е. с ссылками на Int1/Int2, это занимает около 10 минут. Когда я запускаю Profiler и смотрю, что на самом деле происходит, я вижу, что 99% случаев, когда двигатель занят возвратом данных из встроенного запроса. Похоже, что MySQL на самом деле работает
select ... from big_table_with_millions_of_rows
немного встроенного запроса один раз перед нанесением
where id between t.int1 and t.int2
бит до результата. Может ли это быть правдой? Если нет, то что происходит? Я всегда думал, что встроенный SELECT
S были потенциально опасными, потому что они выполняются в строке как последний элемент запроса, но для подобных ситуаций, где начальные SELECT
действительно очень избирательный, это может быть очень эффективным. Кто -нибудь может пролить свет на это?
РЕДАКТИРОВАТЬ: Спасибо за отзыв до сих пор. Я обеспокоен не столько в рядовом характере встроенного запроса, а о том, что он, кажется, не может использовать первичный индекс ключей при столкновении с переменными, а не (одинаковыми) жесткими значениями. Я предполагаю, что если анализ не был запущен в последнее время, то оптимизатор предполагает, что он должен сделать сканирование таблицы, поскольку не знает о распределении данных. Но не должен ли тот факт, что поиск диапазона не выполняется на первичном ключе, не компенсирует это?
Решение
Если коррелированная подзадность не оптимизирована хорошо, попробуйте этот запрос:
select
t.id
, t.int1
, t.int2
, count(*)
from myTable t
left outer join big_table_with_millions_of_rows b
on (b.id between t.int1 and t.int2)
where
....
group by t.id
Это должно оптимизировать намного лучше.
По вашему обновлению: верно, MySQL - не самые сложные RDBMS на рынке с точки зрения оптимизации. Не удивляйтесь, когда MySQL не может оптимизировать такие угловые дела, как это.
Я фанат MySQL за его простоту использования и открытого исходного кода и все эти хорошие вещи, но правда в том, что его конкуренты намного опережают MySQL с точки зрения технологий. У каждого RDBMS есть некоторые «слепые пятна», но MySQL, кажется, больше.
Также убедитесь, что вы используете последнюю версию MySQL. Они улучшают оптимизатор в каждом выпуске, так что вы можете получить лучшие результаты с более новой версией.
Другие советы
Старайтесь избегать коррелированных подразделений, используя Join, если можете.
Посмотрите это отличное видео на MySQL Performance на YouTube. Анкет Отправляйтесь в 31:00.
Если подзадные ссылки поля из его содержащегося запроса, подзадность должна быть повторно заново на каждом ряду в содержащемся запросе, потому что ссылочные поля могут отличаться в каждом ряду. Если он полностью автономен, его можно запустить один раз, прежде чем внешний запрос начнет обработку.