Пагинация и производительность LIMIT на больших списках.

Yoskaldyr

"Спамер"
Партнер клуба
Задача классическая - есть обычная пагинация отсортированного списка (сортируется по полю с индексом), за небольшим исключением список который надо обрабатывать состоит из 300К и более записей. Задача отобразить любую страницу из списка за вменяемое время.
Обычный LIMIT очень хорошо подходит для пагинации, но его основная проблема - с ростом числа пропускаемых полей увеличивается время запроса, даже когда идет выборка по индексу. И увеличивается ощутимо. Если к примеру запрос с LIMIT 10,20 выполнится практически моментально, то LIMIT 300000,300010 уже займет порядка секунды (даже если используются memory таблицы). А если список будет больше например 1млн записей????
А сейчас в вебе генерация всей страницы должна занимать значительно меньше 1 сек и неприемлемо когда sql-запрос будет занимать больше 1 сек.
Да все зависит от мощностей процессора, можно уменьшить время за счет наращивания мощностей. Но это не спортивно как-то.

Так же есть еще один момент - значения по которым сортируется список постоянно обновляются, не все сразу конечно, а 3-4 записи в сек. Поэтому делать расчет позиции по крону (раз минуту например), а потом использовать обычный where для выбора элементов конкретной страницы тоже не представляется возможным.

Кто сталкивался с такой проблемой и если сталкивался то как решал ее?

Вопрос навеян этой темой. Но т.к. проблема не создании пагинации, а в решении проблем производительности, то создаю новую тему. Да у меня используется mysql, но насколько я знаю такая проблема есть и у постгреса, поэтому пишу здесь, а не в разделе чисто mysql.

P.S. Вообще-то я уже решил как это сделать, и в продакшене уже больше года, но решение все еще не совсем нравится и кажется немного велосипедным, поэтому и спрашиваю может есть какие стандартные решения.
 

Фанат

oncle terrible
Команда форума
Для начала стоит спросить себя - для кого предназначается листалка в миллион страниц?
 

Redjik

Джедай-мастер
Explain точно показывает, что по индексу LIMIT идет?
На 100к не замечал проблем...
 

Фанат

oncle terrible
Команда форума
Redjik
А индекс мало на лимит влияет. Проблема-то известная.

Yoskaldyr
Вообще-то я не говорил о каких-то изменениях и тем более - ТЗ.
Я предлагал просто задуматься.
 

Redjik

Джедай-мастер
Фанат
где можно почитать - гугл всякую фигню выдает
напеример ORDER BY RAND() сразу находит
 

Фанат

oncle terrible
Команда форума
Ну, например, на форуме несколько раз обсуждалось.

Но я могу и своими словами объяснить.
Лимит включается после того, как индекс уже отработал.
А лимит тупо перебирает датасет в 100500 записей в оисках 100510-й.
 

Фанат

oncle terrible
Команда форума
Но заставить работать индекс можно.
Если выбирать только те данные, которые уже лежат в индексе.
И уже потом по ним выбирать актуальные данные.
 

Фанат

oncle terrible
Команда форума
я имею в виду, что метод неспортивный.
Это, конечно, вариант - и неплохой, кстати.
Но классической пагинацией не является.
 

Yoskaldyr

"Спамер"
Партнер клуба
Поставим вопрос по другому. Можно ли сделать быструю и честную пагинацию (все ссылки выше - это варианты обхода проблемы, а не решение ее) с использованием чего либо еще в довесок к mysql или вообще без mysql?
Я понимаю что в большинстве случаев достаточно приблизительной пагинации (тогда все делается довольно просто), но всетаки бывают случаи когда надо именно так и не иначе и все обходные варианты не подойдут.

P.S. Еще раз повторю, что решение есть, правда велосипедное и юзает не только мускуль и да ограничением на 2млн записей в списке, но работает быстро. Просто думал что может еще какие есть...
 

Yoskaldyr

"Спамер"
Партнер клуба
Yoskaldyr
Вообще-то я не говорил о каких-то изменениях и тем более - ТЗ.
Я предлагал просто задуматься.
Я вообще-то прежде чем что-то делать стараюсь думать ;)
И понятно что в 99% пагинацию можно сделать последовательной по принципу вперед назад и все будет работать быстро и без каких либо проблем.
Здесь больше был спортивный интерес. Ведь с одной стороны задача до банального примитивная - пагинация, но со своими нюансами на больших объемах
 

Фанат

oncle terrible
Команда форума
гм, это реальная задача?
таблица с мильёном записей обновляется 3-4 раза в секунду?
а какие на ней индексы?
 

Yoskaldyr

"Спамер"
Партнер клуба
гм, это реальная задача?
таблица с мильёном записей обновляется 3-4 раза в секунду?
а какие на ней индексы?
Задача реальная (в продакшене уже больше года). Рейтинг. Идет парсинг числовых данных с другого ресурса и постоянное обновление в среднем 3-5 записей в сек.
Всего записей в базе порядка 3млн. Правда в рейтинге участвует 350К. Раньше в рейтинге больше было порядка 900К, но памяти стало жалко поэтому ограничил минимальный порог входа в рейтинг, да и перепроверку данных тогда можно делать более часто, т.е. рейтинг более адекватный выходит.

Если написать сразу на чем сделано, то не будет никакого обсуждения - тему создал для того что бы узнать а есть ли еще какие решения...
 

Фанат

oncle terrible
Команда форума
С чего ты взял, что не будет никакого обсуждения?
Здесь ничто не любят сильнее, чем обгадить чужое решение :)

Обновление или добавление записей? обновление затрагивает индексы?

кстати, что мешает при обновлении сразу же обновлять и кэш?
 

Yoskaldyr

"Спамер"
Партнер клуба
С чего ты взял, что не будет никакого обсуждения?
Здесь ничто не любят сильнее, чем обгадить чужое решение :)

Обновление или добавление записей? обновление затрагивает индексы?

кстати, что мешает при обновлении сразу же обновлять и кэш?
Обновлять кеш из 12000 страниц???? Тогда уж проще действительно по крону 1 запросом (пусть будет сек 5) выполняться проставлять номера страниц для каждой записи.

Ладно сортированный список хранится в редисе, где есть возможность выбрать но порядковому номеру определнное значение. Значения в данном случае - это Id-шники записей в mysql, а выборка по ид мгновенная. Но костыльно, велосипедно и неспортивно. Хочется более красивого решения.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Даже гугл в результатах поисковой выдачи не показывает больше 100 страниц.
 

Фанат

oncle terrible
Команда форума
В общем, не знаю. я думал, у меня есть хорошее решение, сейчас попробовал его - а оно нифига не работает.

В общем, судя по всему, наилучшее решение - это
Do not let user go to deep pages, redirect him to http://en.wikipedia.org/wiki/Internet_addiction_disorder after certain number of pages
как сказано в http://www.scribd.com/doc/14683263/Efficient-Pagination-Using-MySQL - а регалии перечислены отнюдь не слабые.

и если уж на Перкона Перфоманс конференции ничего лучше не придумали, то вряд ли оно есть.
Твое собственное решение, насколько я понимаю - это некий кэш/денормализация. (ага, ну вот так и есть)
 
Сверху