Краткий сценарий: таблица с более чем 16 миллионами записей [размером 2 ГБ]. Чем выше смещение LIMIT в SELECT, тем медленнее становится запрос при использовании ORDER BY * primary_key *
Так
SELECT * FROM large ORDER BY `id` LIMIT 0, 30
занимает гораздо меньше, чем
SELECT * FROM large ORDER BY `id` LIMIT 10000, 30
Это только заказывает 30 записей и то же самое так или иначе. Так что это не накладные расходы от ORDER BY.
Теперь при получении последних 30 строк это занимает около 180 секунд. Как я могу оптимизировать этот простой запрос?
mysql
performance
sql-order-by
limit
Rahman
источник
источник
Ответы:
Обычно старшие смещения замедляют запрос, так как запрос должен отсчитывать первые
OFFSET + LIMIT
записи (и принимать толькоLIMIT
их). Чем выше это значение, тем дольше выполняется запрос.Запрос не может быть выполнен правильно,
OFFSET
потому что, во-первых, записи могут быть разной длины, и, во-вторых, могут быть пропуски в удаленных записях. Необходимо проверить и посчитать каждую запись на своем пути.Предполагая , что
id
являетсяPRIMARY KEY
изMyISAM
таблицы, вы можете ускорить его, используя этот трюк:Смотрите эту статью:
источник
ORDER BY
или он охватывает все необходимые поля, этот обходной путь не требуется.postgresql
. Это специфичный для MySQL ответ.У меня была точно такая же проблема. Учитывая тот факт, что вы хотите собрать большой объем этих данных, а не определенный набор из 30, вы, вероятно, будете запускать цикл и увеличивать смещение на 30.
Итак, что вы можете сделать вместо этого:
WHERE id > lastId limit 0,30
Таким образом, вы всегда можете иметь нулевое смещение. Вы будете поражены улучшением производительности.
источник
MySQL не может перейти непосредственно к 10000-й записи (или 80000-му байту, как вы предлагаете), потому что он не может предположить, что он упакован / упорядочен таким образом (или что он имеет непрерывные значения от 1 до 10000). Хотя это может быть так в действительности, MySQL не может предположить, что нет дыр / пробелов / удаленных идентификаторов.
Таким образом, как заметил Бобс, MySQL должен будет извлечь 10000 строк (или пройти через 10000-ые записи индекса
id
), прежде чем найти 30 для возврата.РЕДАКТИРОВАТЬ : Чтобы проиллюстрировать мою точку зрения
Обратите внимание, что хотя
будет медленно (э) ,
будет быстрым (er) и будет возвращать те же результаты при условии отсутствия пропущенных
id
s (т. е. пропусков).источник
Я нашел интересный пример для оптимизации запросов SELECT ORDER BY id LIMIT X, Y. У меня 35 миллионов строк, поэтому мне понадобилось около 2 минут, чтобы найти диапазон строк.
Вот хитрость:
Просто поместите WHERE с последним идентификатором, который вы получили, чтобы увеличить производительность. Для меня это было от 2 минут до 1 секунды :)
Другие интересные трюки здесь: http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/
Это работает также со строками
источник
Отнимающая много времени часть двух запросов извлекает строки из таблицы. Логически говоря, в
LIMIT 0, 30
версии нужно извлечь только 30 строк. ВLIMIT 10000, 30
версии оценивается 10000 строк и возвращается 30 строк. Может быть некоторая оптимизация может быть сделана в процессе чтения данных, но учтите следующее:Что если в запросах есть предложение WHERE? Движок должен вернуть все подходящие строки, а затем отсортировать данные и, наконец, получить 30 строк.
Также рассмотрим случай, когда строки не обрабатываются в последовательности ORDER BY. Все подходящие строки должны быть отсортированы, чтобы определить, какие строки возвращать.
источник
Для тех, кому интересно сравнение и цифры :)
Эксперимент 1: набор данных содержит около 100 миллионов строк. Каждая строка содержит несколько полей BIGINT, TINYINT, а также два поля TEXT (намеренно), содержащие около 1 тыс. Символов.
SELECT * FROM post ORDER BY id LIMIT {offset}, 5
SELECT t.* FROM (SELECT id FROM post ORDER BY id LIMIT {offset}, 5) AS q JOIN post t ON t.id = q.id
... WHERE id>xxx LIMIT 0,5
здесь не фигурирует, поскольку он должен быть постоянным.Эксперимент 2: похожая вещь, за исключением того, что в одной строке есть только 3 BIGINT.
источник