Я собственно пишу свою мини либы, в которой мне потребовалось организовать пагинацию (приватные сообщения, и если количество переписок превышает разумные границы, сделать перенос на следующую страницу) Но начитавшись умных статей - я узнал, что оказывается команда Код (Text): limit ofsset очень сильно просаживается с увеличением количества записей. Вопрос чем её тогда заменить? Как её заменяют в популярных приложениях ( например этот форум?)
Первый раз слышу. Ссылку на умную статью можно? Люди, которые такие вещи пишут, обычно указывают и чем заменить. Ничем не заменить, при большом количестве записей и большой нагрузке кэшировать результаты выборок и всё.
--- Добавлено --- https://ruhighload.com/Постраничный+вывод+в+mysql Это первая статья. Еще парочка, в закладках на другой машине у меня, как доберусь и если не забуду скину, но там тот же самый смысл.
Там же написано, что можно заменить условием с id первой записи на странице, который вы передаете в адресе. Правда, тут есть риск, что над вашим сайтом начнут издеваться, проставляя ссылки с id записи из середины какой-то страницы. P.S. count часто кэшируем триггерами в записи самого списка. И это не из-за InnoDB, который в основном и используем, а чтобы в принципе не выполнять лишний запрос. Плюс это значение часто требуется в метаданных и без формирования самого списка.
Да, но тут беда в том, что могут быть ID не попорядку, а именно с дырками (и вообще как бы порядок ID не рекомендуется использовать как основу, для сортировки и т.д.) Как это кэшируем тригерррами в записи самого списка? Это как?
Тут смысл не в том, чтобы использовать id вместо нумерации. Важен только хронологический порядок, т.е. предполагается что чем больше id, тем позднее создана соотв. запись. Поставьте триггеры на добавление и удаление записи, в которых обновляйте счетчик(и) родительских по отношению к элементам данного списка записей.
Кстати, а это где написано? Обычно наоборот пытаются сделать оптимизацию с использованием этого поля, чтобы не индексировать поле с временем. --- Добавлено --- Ну если оч. хоЦА, можете в качестве базы для постраничной навигации использовать время
Кстати вот вспомнил умные статьи - и вот какое лечение они предлагают https://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ Код (Text): SELECT l.id, value, LENGTH(stuffing) AS len FROM ( SELECT id FROM t_limit ORDER BY id LIMIT 150000, 10 ) o JOIN t_limit l ON l.id = o.id ORDER BY l.id По сути - внутренний запрос только по индесированному полю и к этому результату уже join
Кстати только что протестировал дает достаточно существенную разницу даже после 100.000 записей Она особенно видна становится когда сильно вырастает offset limit 10 offset 10000 А чет тут redis.io поможет?
Тест этого велосипеда - 3 млн записей в таблице http://joxi.ru/a2XEQ99uyR8GjA - это с велосипедом без велосипеда http://joxi.ru/KAgdGaaCgplLvr
С LIMIT offset, number тормоза возникают на больших offset. Это происходит потому, что MySQL вынужден пролистать все записи до offset чтобы в итоге выдать тебе только нужный кусочек. Выхода два: 1. Найти способ заменить его на LIMIT number. То есть без смещения. Вместо него добавляем условие в WHERE и желательно по индексированному полю(ям). Это то, о чём писал @miketomlin "…можно заменить условием с id первой записи на странице" — не обязательно id, используем то поле(я), по которому(ым) идет сортировка в этой выдаче. 2. Сохранить LIMIT offset, number, но уменьшить объем данных, которые MySQL будет перебирать, отсчитывая записи до offset. То есть упростить до предела, избавиться от некритичных для счетчика джойнов и лишних полей. Оставить во фразе select только id, например. Используем этот упрощенный запрос как под-запрос и уже во внешнем запросе добавляем все оставшиеся таблицы и поля. Это то, что ты @glorsh66 нашел в этом коменте. Я только сформулировал в общем виде. --- Добавлено --- Я не вникал как это в движке Xenforo который установлен здесь, но я знаю как это решено в семействе форумов PunBB/FluxBB — по второму варианту. Используется облегчённый быстрый запрос, а найденные ID уже подставляются в главную выборку. https://github.com/fluxbb/fluxbb/blob/master/viewtopic.php#L217
Благодарю за отличный ответ!☻ --- Добавлено --- Небольшой оффтоп ☻ На гитхабе такая строчка - Код (Text): $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$id.' ORDER BY id LIMIT '.$start_from.','.$pun_user['disp_posts']) or error('Unable to fetch post IDs', __FILE__, __LINE__, $db->error()); Но что такое Код (Text): or error Что это за конструкция такая?
@glorsh66, OR - логический оператор 'ИЛИ'. От || приоритетом выполнения. error() в данном случае - функция.
PHP: blablabla() or unzununz(); это работает так: если blablabla() выполнилось с непустым результатом (что приравнивается к значению true), то вторая функция выполняться не будет. но если blablabla() вернуло 0 | false | null, короче "пустое значение", то будет вызвано то, что правее "or". все методы объекта $db в той библиотеке возвращают непустой результат в случае успеха. то есть error() не должен выполняться по идее. error() выводит ошибку и заканчивается exit() чтобы дальше уже ничего не выполнялось. понятно?
Небольшой оффтоп ☻ На гитхабе такая строчка - Код (Text): $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$id.' ORDER BY id LIMIT '.$start_from.','.$pun_user['disp_posts']) or error('Unable to fetch post IDs', __FILE__, __LINE__, $db->error()); Но что такое Код (Text): or error Да)
Собрался прочел статью и как то странно все это всегда считал что офсет работает по принципу бинарного поиска.
если по индексу - то да поэтому суть статьи совсем не в том, чтобы отказаться от оффсета оффсет используется там где есть запрос, к запросу условие, к условию оффсет эссно это даёт необходимость построить всё услоие и все пересечения всех индексов где-то в памяти. суть статьи в том, чтобы так построить свою архитектуру, чтобы оффсет стал не нужен тогда можно будет выбирать по id или любому другому уникальному ключу.