Подтвердить что ты не робот

Почему смещение MYSQL выше LIMIT замедляет запрос вниз?

Сценарий вкратце: таблица с более чем 16 миллионами записей [размером 2 ГБ]. Чем выше LIMIT offset с SELECT, тем медленнее будет запрос при использовании ORDER BY * primary_key *

So

SELECT * FROM large ORDER BY `id`  LIMIT 0, 30 

занимает гораздо меньше, чем

SELECT * FROM large ORDER BY `id` LIMIT 10000, 30 

Это только заказывает 30 записей и то же самое в любом случае. Так что это не накладные расходы от ORDER BY.
Теперь, получая последние 30 строк, требуется около 180 секунд. Как я могу оптимизировать этот простой запрос?

4b9b3361

Ответ 1

Нормально, что более высокие смещения замедляют запрос вниз, так как запрос должен отсчитывать первые записи OFFSET + LIMIT (и брать только LIMIT из них). Чем выше это значение, тем дольше выполняется запрос.

Запрос не может перейти прямо к OFFSET, потому что, во-первых, записи могут иметь разную длину и, во-вторых, могут быть пробелы из удаленных записей. Он должен проверять и считать каждую запись на своем пути.

Предполагая, что id является PRIMARY KEY таблицы MyISAM, вы можете ускорить его, используя этот трюк:

SELECT  t.*
FROM    (
        SELECT  id
        FROM    mytable
        ORDER BY
                id
        LIMIT 10000, 30
        ) q
JOIN    mytable t
ON      t.id = q.id

См. статью:

Ответ 2

У меня была одна и та же проблема. Учитывая тот факт, что вы хотите собрать большое количество этих данных, а не определенный набор из 30, вы, вероятно, будете запускать цикл и увеличивать смещение на 30.

Итак, что вы можете сделать, это:

  • Удерживать последний идентификатор набора данных (30) (например, lastId = 530)
  • Добавьте условие WHERE id > lastId limit 0,30

Таким образом, вы всегда можете иметь смещение ZERO. Вы будете поражены улучшением производительности.

Ответ 3

MySQL не может перейти непосредственно к 10000-й записи (или 80000-й байт, как вы предлагаете), потому что он не может предположить, что он упакован/упорядочен как этот (или что он имеет непрерывные значения от 1 до 10000). Хотя в действительности это может быть так, MySQL не может предположить, что нет дыр/пробелов/удаленных идентификаторов.

Итак, как отмечали бобы, MySQL должен будет получить 10000 строк (или пройти через 10000-й записи индекса на id), прежде чем найти 30 для возврата.

РЕДАКТИРОВАТЬ. Чтобы проиллюстрировать мою точку.

Обратите внимание, что хотя

SELECT * FROM large ORDER BY id LIMIT 10000, 30 

будет медленным (er),

SELECT * FROM large WHERE id >  10000 ORDER BY id LIMIT 30 

будет быстрым (er) и вернет те же результаты, если нет отсутствующих id (т.е. пробелов).

Ответ 4

Отнимающая много времени часть двух запросов извлекает строки из таблицы. Логически говоря, в версии LIMIT 0, 30 необходимо восстановить только 30 строк. В версии LIMIT 10000, 30 оценивается 10000 строк и возвращается 30 строк. Может быть какая-то оптимизация может быть выполнена моим процессом чтения данных, но рассмотрим следующее:

Что делать, если в запросах есть предложение WHERE? Механизм должен возвращать все строки, которые квалифицируются, а затем сортировать данные и, наконец, получить 30 строк.

Также рассмотрим случай, когда строки не обрабатываются в последовательности ORDER BY. Все квалификационные строки должны быть отсортированы для определения возвращаемых строк.

Ответ 5

Я нашел интересный пример для оптимизации запросов SELECT ORDER BY id LIMIT X, Y. У меня 35 миллионов строк, поэтому для поиска ряда строк потребовалось 2 минуты.

Вот трюк:

select id, name, address, phone
FROM customers
WHERE id > 990
ORDER BY id LIMIT 1000;

Просто поставьте ГДЕ с последним идентификатором, который вы сильно увеличили производительность. Для меня это было от 2 минут до 1 секунды:)

Другие интересные трюки здесь: http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/

Он также работает со строками