|
|
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Всем привет! Прошу теоретическо-стратегической помощи в довольно конкретном вопросе. Уверен опытные бекенд программисты решали эту задачу тысячи раз, я хочу знать самое оптимальное решение. Задача : В таблице десятки миллионов строк (одна таблица уже около 40ГБ и растет) Нужно по определенному фильтру сделать SELECT (в результате получается несколько тысяч результатов, например 87300), и на клиент передать только 50 результатов. Но при этом сообщить ему (клиенту) также и общее количество результатов (87300). Т.е. классический пейджинг с limit/offset Я вижу два варианта решения 1) Вариант : делаю два запроса: 1. COUNT (SELECT..WHERE....) - получаю total 2. SELECT..WHERE....LIMIT=50 - получаю 50 результатов 2) Вариант : выбираю все при помощи hibernate (или чего-то аналогичного) в java List<Results>, беру list.size(), и выбираю 50 первых результатов В первом случае меня смущает то, я всегда делаю два запроса подряд к базе (вместо одного) Во втором то, что я выгружаю 87300 объектов в оперативную память в JVM (а при этом аналогичный запрос приходит он нескольких сотен пользователей одновременно и для каждого нужно все результаты тянуть в оперативку) Правильно ли я понимаю работу памяти во втором случае? Какой вариант "дешевле" и принято использовать, как наиболее рациональный? Может есть третий путь? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.04.2016, 23:20 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
psyh1031) Вариант : делаю два запроса:Можно одним запросом (Oracle): Код: sql 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 09.04.2016, 23:50 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Пардон, это не совсем то, что нужно ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 00:03 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
psyh103, hibernate не будет 87300 загружать - Criteria/HQL/Sort/Limit ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 00:10 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Разве offset/limit правильный подход? Может лучше primaty key < :lastId / limit? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 00:12 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Usman Код: sql 1. Можно использовать как подзапрос: Код: sql 1. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 01:09 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
rdmpsyh103, hibernate не будет 87300 загружать - Criteria/HQL/Sort/Limit А что он тогда в ListArray результатов имеет? ссылки только на строки в таблице что ли? rdmРазве offset/limit правильный подход? Может лучше primaty key < :lastId / limit? Да, действительно так выглядит правильней, спасибо за рекомендацию ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 01:13 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
psyh103В таблице десятки миллионов строкЭто что-то вроде архива (т.е. данные в таблицах не подвергается изменениям) ?psyh103Нужно по определенному фильтру сделать SELECTЕсть ли вероятность того, что можно предугадать действия пользователя (хотя бы частично) ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 01:16 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
UsmanЭто что-то вроде архива (т.е. данные в таблицах не подвергается изменениям) нет не архив, данные постоянно обновляются UsmanЕсть ли вероятность того, что можно предугадать действия пользователя (хотя бы частично) ? Если имеется ввиду набор фильтров, то почти всегда один и тот же фильтр, а вот результаты постоянно изменяются, т.к. в той большой таблице все время меняются данные, которые влияют на выборку по фильтру ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 01:22 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
UsmanUsman Код: sql 1. Можно использовать как подзапрос: Код: sql 1. Спасибо, выглядит, как хорошее решение. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 01:23 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
psyh103, конкретный вид sql строки будет зависить от используемой базы. при большом объеме данных count лучше вынести в отдельный запрос, он будет выполняться дольше, чем запрос с выводом 50 записей. сначала выведутся данные, а с задержкой общее число записей. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 04:17 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
UsmanUsman Код: sql 1. Можно использовать как подзапрос: Код: sql 1. надеюсь, что ТС тоже оракл, а также, что select count не будет выполняться в каждой строке. но зачем иметь столбеу с одни числом повторяемым 88 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 04:25 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Usmanпропущено... Можно использовать как подзапрос: Код: sql 1. надеюсь, что у ТС тоже оракл, а также, что select count не будет выполняться в каждой строке. но зачем иметь столбец с одни числом повторяемым 80 0000+ раз? память надо разумно использовать ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 04:30 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
UsmanUsman Код: sql 1. Можно использовать как подзапрос: Код: sql 1. сначала выполнится запрос отбирающий 80 000+ строк, потом из него выберется 50 строк — это очень долго. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 04:45 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Очевидно, что рабочий вариант это только первый, как именно его реализовывать - одним запросом, в котором доп.колонкой добавить общее количество или двумя отдельными запросами уже вопрос вкуса и конкретной СУБД, это все будут работающие варианты. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.04.2016, 20:25 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
just_vladimirОчевидно, что рабочий вариант это только первый+512 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 01:42 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Usmanjust_vladimirОчевидно, что рабочий вариант это только первый+512 только порядок селектов обратный ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 03:59 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
psyh1031) Вариант : делаю два запроса: 1. COUNT (SELECT..WHERE....) - получаю total 2. SELECT..WHERE....LIMIT=50 - получаю 50 результатов Вполне стандартный подход. Все так делают. psyh1032) Вариант : выбираю все при помощи hibernate (или чего-то аналогичного) в java List<Results>, беру list.size(), и выбираю 50 первых результатов В hibernate много такого чего в чем-то аналогичном может и не быть. psyh103В первом случае меня смущает то, я всегда делаю два запроса подряд к базе (вместо одного) Ну, если это смущает только вас и не смущает DBA, то, наверное, не страшно. psyh103Во втором то, что я выгружаю 87300 объектов в оперативную память в JVM (а при этом аналогичный запрос приходит он нескольких сотен пользователей одновременно и для каждого нужно все результаты тянуть в оперативку) Ну, зачем так сразу. Hibernate может много чего предложить для решения этого вопроса. Например существует такой метод http://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/Session.html#createFilter-java.lang.Object-java.lang.String- Если, я правильно понял, то ему можно скормить ленивую коллекцию и потом загружать ее постраничено через Query Другая сторона вопроса это кэш второго уровня. Не зачем читать все объекты из БД для каждого пользователя. Можно их сформировать из кэша. Правда, тут есть нюанс, в виде того как работает кеш. Он собирает новые объекты из слепка. Поэтому каждый пользователь расходует память. Но это вполне можно оптимизировать, если иметь, например, список id. В общем, есть над чем подумать. psyh103[b]Правильно ли я понимаю работу памяти во втором случае? Да, но есть варианты. psyh103Какой вариант "дешевле" и принято использовать, как наиболее рациональный? Два запроса к БД, скорее всего, будут рациональнее. Но если между сервером и БД воткнуть толковый кэш, то будет "еще более рационально". Поэтому я за Hibernate + Paging любым удобным для вас способом (JPQL, HQL, Criteria API, Lazy Collection) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 08:24 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
BlazkowizcВполне стандартный подход. Все так делают. Все, кто не понимает, что делает. Вполне стандартная ошибка. Правильные подходы следующие: - иметь в таблице поле, подходящее для счётчика записей и делать в цикле выбор диапазонов по этому счётчику. Например, в Oracle уже есть такое поле ROWID. - в процедурном SQL соответствующей СУБД делать в цикле выборку с использованием курсора. Метод довольно универсальный, поскольку в популярных СУБД курсоры есть. Хотя синтакис зависит от СУБД. Неправильно использование OFFSET... LIMIT и Hibernate. Способ с OFFSET...LIMIT неэффективен, потому что будут считываться все записи с начала и уже потом из них выбираться нужные. Способ с Hibernate неправильгный потому, что в нём Hibernate испольхуется не по назначению. Следовательно, вряд ли можно надеяться на особую эффективность. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 11:22 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Partisan MСпособ с OFFSET...LIMIT неэффективен, потому что будут считываться все записи с начала и уже потом из них выбираться нужные. Реквестирую пруфлинк по этому поводу ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 11:42 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Partisan MВсе, кто не понимает, что делает. Вполне стандартная ошибка. Ой, да. Partisan M- иметь в таблице поле, подходящее для счётчика записей и делать в цикле выбор диапазонов по этому счётчику. Например, в Oracle уже есть такое поле ROWID. Ага. Еще один ID, который нужно генерировать правильным образом. Я понимаю, что кроме Oracle других RDBMS не существует. Но все же, у ТС может и MySQL оказаться. Partisan M- в процедурном SQL соответствующей СУБД делать в цикле выборку с использованием курсора. Метод довольно универсальный, поскольку в популярных СУБД курсоры есть. Хотя синтакис зависит от СУБД. Курсор. На трехзвенке. Опять, с условием, что у нас только Oracle? Partisan MНеправильно использование OFFSET... LIMIT и Hibernate. Способ с OFFSET...LIMIT неэффективен, потому что будут считываться все записи с начала и уже потом из них выбираться нужные. Способ с Hibernate неправильгный потому, что в нём Hibernate испольхуется не по назначению. Следовательно, вряд ли можно надеяться на особую эффективность. Возможно. Если автор им особо и не пользуеются и изучать не хочет, то и приплетать ORM, наверное, смысла нет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 12:01 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
Partisan M- в процедурном SQL соответствующей СУБД делать в цикле выборку с использованием курсора. Содержит плюсы и минусы. Главный из последних, заключен в сценарии, при котором пользователь почти никогда не переходит на последнюю страницу. А просто меняет условие посмотрев первые одну-две. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 12:16 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
just_vladimirPartisan MСпособ с OFFSET...LIMIT неэффективен, потому что будут считываться все записи с начала и уже потом из них выбираться нужные. Реквестирую пруфлинк по этому поводу если Order by есть то неэффективно. а так вполне себе эффективно. (postgresl) Limit (cost=1.15..1.73 rows=5 width=857) (actual time=0.042..0.054 rows=5 loops=1) -> Seq Scan on individual (cost=0.00..228311.98 rows=1979148 width=857) (actual time=0.016..0.039 rows=15 loops=1) Filter: (pol_id = 1) Rows Removed by Filter: 9 Total runtime: 0.124 ms тут правильнее будет сказать что если offset приближается к максимальному количеству строк Код: plsql 1. то становится неэффективным тут лучше уже Код: sql 1. Но редкий пользователь дошагает до 100000-ой страницы т.к. что в общем случае OFFSET...LIMIT вполне эффективно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 14:39 |
|
||
|
Пейджинг с limit/offset и общее количество элементов
|
|||
|---|---|---|---|
|
#18+
llemingjust_vladimirпропущено... Реквестирую пруфлинк по этому поводу если Order by есть то неэффективно. а так вполне себе эффективно. (postgresl) Limit (cost=1.15..1.73 rows=5 width=857) (actual time=0.042..0.054 rows=5 loops=1) -> Seq Scan on individual (cost=0.00..228311.98 rows=1979148 width=857) (actual time=0.016..0.039 rows=15 loops=1) Filter: (pol_id = 1) Rows Removed by Filter: 9 Total runtime: 0.124 ms тут правильнее будет сказать что если offset приближается к максимальному количеству строк Код: plsql 1. то становится неэффективным тут лучше уже Код: sql 1. Но редкий пользователь дошагает до 100000-ой страницы т.к. что в общем случае OFFSET...LIMIT вполне эффективно. Ну Вы как бы подтверждаете обратное, что у limit/offset все хорошо, а то некоторые голословно кидаются в него фекалиями, называя ошибкой его использование. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.04.2016, 16:08 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=39211818&tid=2124170]: |
0ms |
get settings: |
6ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
191ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
47ms |
get tp. blocked users: |
1ms |
| others: | 249ms |
| total: | 526ms |

| 0 / 0 |
