|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
размышления есть подзапрос: объедены две выборки через union all набор строк в подзапросе может достигать нескольких сотен тыс на общий результат накладывается еще куча джоинов не увеличивающих и не уменьшающих общее количество row нет возможности лимит и оффсет перенести в подзапрос, (к сожалению используемый движок не позволяет, limit всегда в конце запроса) есть общая сортировка по дате (дата определяется в обоих частях подзапроса, но из разных источников) лимитом отбирается стабильно максимум 10 строк, все зависит от пагинации Можно ли в этом случае ускорить пагинацию, что бы не собирать все строки, или в текущем варианте бесполезно? ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 17:55 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Legushka, что сказать то хотели, барин ? что не умеет он лимит поверх аппенда внутрь оппендуемого вставлять ? ну дык давно известно. даже хуже -- добавляшь в ордер бай в конец уникализирующее поле -- и все с ис с лимитом вдоль скатывается в лимит после сорта всего (всего !) , блин, скана. всё в ваших руках ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 18:14 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
qwwq, а есть какие нибудь методы как решить? в голову ничего не приходит не хочется ковырять все записи что бы потом отобрать только 10 ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 18:25 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Legushkaqwwq, а есть какие нибудь методы как решить? в голову ничего не приходит не хочется ковырять все записи что бы потом отобрать только 10 писать запросы руками и вставлять limit 10 в обе части union all насколько поможет - не факт но это единственное куда вообще можно копать. Что там позволяет или нет ваш движек - ваши проблемы, можно всегда запрос в хранимку засунуть если очень хочется. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 19:17 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Legushka Можно ли в этом случае ускорить пагинацию, что бы не собирать все строки, или в текущем варианте бесполезно? Если у вас еще и offset - то почти невозможно почти, хотя если Limit+offset обычно небольшие (т.е. ходят на первые страницы) то можно сделать финт ушами вида select * from (select ... LIMIT [offset+limit] ) UNION ALL (select ... LIMIT [offset+limit] ) ORDER BY ... OFFSET offset LIMIT limit; PS: в приличных местах за неограниченный (т.е не первые 5-10 страниц) paging через limit/offset - бьют по лицу (это крайне плохо заканчивается для базы, особенно весело когда приходит какой то тупой робот и начинает через limit/offset перебирать несколько миллионов страниц последовательно). -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 19:25 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Maxim Boguk , да там лимит и офсет добавляется движком, к сожалению движок нельзя переделать что бы он лимиты в указанноое место вставлял а что если подзапрос вида union all как нибудь развернуть на join'ах (cross join, full outer join) ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 19:42 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Legushka, теоретиццки он может мердж--аппенд выполнить в одной связке с лимитом. т.е. партиции при наличии во всех индексов того же порядка, что и внешний одербай к головной. (но только с точностью до буквы. взять по 10+ (Вычитать все узлы неуникального) и отресортить и опять отрезать 10 ( или (до)сортить первенца в процессе,, и обрезать вычитку из отстающих ..) -- вот это всё оно не умеет. если вы научитесь сами руками фетчить всё, что юнайтите, позаписьно дёшево вдоль вашего порядка -- то можете сами вовремя астанавицца. а увидеть, что внутренности юниона (шире -- аппенда) можно дёшево смёрджить с минимальным ресортом и оверфетчем, в общем случае оно не умеет. а за пагинацию оффсетом таки руки отрывать бы надо бы. но вот всё у них так -- некому свистоперделки писать будет. ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 20:08 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
глянул на разницу планов если бы лимит и офсет отработал внутри подзапроса и снаружи уже большой выигрышь на внешних join получается (всего 10 раз вместо 100k ) буду трясти разработчиков движка что бы реализовали возможность вставки лимита в любую часть запроса) ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 20:12 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Legushkaглянул на разницу планов если бы лимит и офсет отработал внутри подзапроса и снаружи уже большой выигрышь на внешних join получается (всего 10 раз вместо 100k ) буду трясти разработчиков движка что бы реализовали возможность вставки лимита в любую часть запроса)А покажите всё же пример с данными и запросом... может быть, что-то всё же можно будет сделать. Это (LIMIT только "снаружи") у Вас единственное ограничение, кстати? ... |
|||
:
Нравится:
Не нравится:
|
|||
12.09.2017, 20:19 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Maxim BogukPS: в приличных местах за неограниченный (т.е не первые 5-10 страниц) paging через limit/offset - бьют по лицу (это крайне плохо заканчивается для базы, особенно весело когда приходит какой то тупой робот и начинает через limit/offset перебирать несколько миллионов страниц последовательно). еще не делал пагинацию ни разу, как правильно реализовать если не через limit/offset, который присутствует в текущей версии? ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 10:30 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
LegushkaMaxim BogukPS: в приличных местах за неограниченный (т.е не первые 5-10 страниц) paging через limit/offset - бьют по лицу (это крайне плохо заканчивается для базы, особенно весело когда приходит какой то тупой робот и начинает через limit/offset перебирать несколько миллионов страниц последовательно). еще не делал пагинацию ни разу, как правильно реализовать если не через limit/offset, который присутствует в текущей версии? Ну вот например есть у вас таблица с постами в форуме. Следующая страница (ссылки) формируется не через limit/offset (которые не будут корректно работать если новые посты например появляются), а через where post_id<(последний post_id на текущей странице) LIMIT сколько вам надо. Т.е. не ссылка на prev page вида skip=50 а ссылка на prev page вида before_post_id=[последний post_id на текущей странице]. Тогда как минимум это во многих случаях будет нормально работать по скорости и главное навигация не будет ломаться при появлении новых постов (что в 100% случаев происходит с limit/offset пагинацией). PS: если у вас там 5-10 страниц максимум - можно и limit/offset а вот если потенциально 1000 страниц - то нет. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 10:41 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
LegushkaMaxim Boguk , да там лимит и офсет добавляется движком, к сожалению движок нельзя переделать что бы он лимиты в указанноое место вставлял а что если подзапрос вида union all как нибудь развернуть на join'ах (cross join, full outer join) легко full join + группировка и прекрасно заменяется ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 10:57 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
правда сомневаюсь что это тебе помоежет. Лимит все равно до джоина применяться не будет ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 10:57 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Постгрес может эффективно выполнить такой запрос - выбрав не все строки, а только нужные по лимиту. Важно, чтобы на каждой таблице существовал нужный индекс, чтобы не требовалось переупорядочивание строк. Тогда сможет использовать Merge Append, джоин по Nested Loop и Limit. Вот пример такого боевого запроса: EXPLAIN (ANALYZE) SELECT usage.req_begin AS usage_req_begin, usage.req_started AS usage_req_started, usage.req_max AS usage_req_max, usage.req_dur AS usage_req_dur, usage.sess_begin AS usage_sess_begin, usage.sess_started AS usage_sess_started, usage.sess_max AS usage_sess_max, usage.sess_dur AS usage_sess_dur, usage.bytes_out AS usage_bytes_out, usage.bytes_out_cached AS usage_bytes_out_cached, usage.max_interval_bytes AS usage_max_interval_bytes, time.year AS time_year, time.month AS time_month, time.day AS time_day, time.hour AS time_hour, time.minute AS time_minute, geo.country AS geo_country, geo.region AS geo_region, useragent.browser AS useragent_browser, useragent.platform AS useragent_platform, backend.torso_id AS backend_torso_id, proto.name AS proto_name, referrer.name AS referrer_name, custom.field1 AS custom_field1, status.code AS status_code, clienturi.client_id AS clienturi_client_id, clienturi.hostname AS clienturi_hostname, clienturi.uri AS clienturi_uri FROM usage INNER JOIN (VALUES (448540, 753, 4176, 210, 67, 11713775, 1, 1, 649608573)) AS ids(time_id, geo_id, useragent_id, backend_id, proto_id, referrer_id, custom_id, status_id, clienturi_parent_id) ON (usage.time_id, usage.geo_id, usage.useragent_id, usage.backend_id, usage.proto_id, usage.referrer_id, usage.custom_id, usage.status_id, usage.clienturi_parent_id) = (ids.time_id, ids.geo_id, ids.useragent_id, ids.backend_id, ids.proto_id, ids.referrer_id, ids.custom_id, ids.status_id, ids.clienturi_parent_id) CROSS JOIN LATERAL (SELECT time.* FROM time WHERE time.id = usage.time_id LIMIT 1) AS time CROSS JOIN LATERAL (SELECT geo.* FROM geo WHERE geo.id = usage.geo_id LIMIT 1) AS geo CROSS JOIN LATERAL (SELECT useragent.* FROM useragent WHERE useragent.id = usage.useragent_id LIMIT 1) AS useragent CROSS JOIN LATERAL (SELECT backend.* FROM backend WHERE backend.id = usage.backend_id LIMIT 1) AS backend CROSS JOIN LATERAL (SELECT proto.* FROM proto WHERE proto.id = usage.proto_id LIMIT 1) AS proto CROSS JOIN LATERAL (SELECT referrer.* FROM referrer WHERE referrer.id = usage.referrer_id LIMIT 1) AS referrer CROSS JOIN LATERAL (SELECT custom.* FROM custom WHERE custom.id = usage.custom_id LIMIT 1) AS custom CROSS JOIN LATERAL (SELECT status.* FROM status WHERE status.id = usage.status_id LIMIT 1) AS status CROSS JOIN LATERAL (SELECT clienturi.* FROM clienturi WHERE clienturi.id = usage.clienturi_id LIMIT 1) AS clienturi ORDER BY usage_bytes_out desc LIMIT 10 Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127.
... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 14:45 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Maxim BogukLegushkaпропущено... еще не делал пагинацию ни разу, как правильно реализовать если не через limit/offset, который присутствует в текущей версии? Ну вот например есть у вас таблица с постами в форуме. Следующая страница (ссылки) формируется не через limit/offset (которые не будут корректно работать если новые посты например появляются), а через where post_id<(последний post_id на текущей странице) LIMIT сколько вам надо. Т.е. не ссылка на prev page вида skip=50 а ссылка на prev page вида before_post_id=[последний post_id на текущей странице]. Тогда как минимум это во многих случаях будет нормально работать по скорости и главное навигация не будет ломаться при появлении новых постов (что в 100% случаев происходит с limit/offset пагинацией). PS: если у вас там 5-10 страниц максимум - можно и limit/offset а вот если потенциально 1000 страниц - то нет. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru это в случае, если ид поста монотонная последовательность ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 16:39 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Maxim BogukLegushkaqwwq, а есть какие нибудь методы как решить? в голову ничего не приходит не хочется ковырять все записи что бы потом отобрать только 10 писать запросы руками и вставлять limit 10 в обе части union all насколько поможет - не факт но это единственное куда вообще можно копать. Что там позволяет или нет ваш движек - ваши проблемы, можно всегда запрос в хранимку засунуть если очень хочется. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru вообще-то думается, что в таком случае результат объединения в общем случаем будет неправильный ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 16:40 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Ролг Хупинэто в случае, если ид поста монотонная последовательность Это в любом случае для стабильно сортируемого множества. А для offset пагинации стабильная сортировка необходима тем более, поэтому применимо. http://use-the-index-luke.com/sql/partial-results/fetch-next-page ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 17:35 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Ролг ХупинMaxim Bogukпропущено... писать запросы руками и вставлять limit 10 в обе части union all насколько поможет - не факт но это единственное куда вообще можно копать. Что там позволяет или нет ваш движек - ваши проблемы, можно всегда запрос в хранимку засунуть если очень хочется. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru вообще-то думается, что в таком случае результат объединения в общем случаем будет неправильный Обоснуйте? ;) Или приведите контрпример. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 18:55 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
LeXa NalBatПостгрес может эффективно выполнить такой запрос - выбрав не все строки, а только нужные по лимиту. Важно, чтобы на каждой таблице существовал нужный индекс, чтобы не требовалось переупорядочивание строк. Тогда сможет использовать Merge Append, джоин по Nested Loop и Limit. дык я об том и писал. 20791161 Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.
или для честного юниона Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.
но позорище в том ,что он не умеет "выбрать последний узел неуникального (в общем случае) индекса, на котором произошло насыщение лимита и отресортив еще раз лимитнутся". даже без аппенда. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
я где-то давно тут показывал, как это обрезать ("без аппенда") скл-м. (в процессе мердж оппенда с индексным префиксом и уникализирующем постфиксе в сортировке это делать, алгоритмически, не сложнее, если у тебя в руках seek, да даже на скл это пишется, в рекурсивеном т.с. стиле. хотя и немного лишнего. проще грубо взять по ломтю, и отресортив все выбросить. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 20:21 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
qwwq, тут кажется не показывал. соврал вот для аппенда то же сделал. т.ч. зафиксирую, чтобы былО куда послать. стыд и срам : Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23.
и через мердж-аппенд с ресортом: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78.
... |
|||
:
Нравится:
Не нравится:
|
|||
13.09.2017, 22:17 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
qwwq, это какая то магия, подставил свои таблицы в ваш пример вот два плана стандартная сортировка https://explain.depesz.com/s/Rz2 и магия) https://explain.depesz.com/s/oEhM я в шоке))) могли бы вы подробно рассказать что происходит на человеческом языке: что это значит: число последних значений неуникального. все сложнее (только в SQL) когда nullable и есть ли подводные камни? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.09.2017, 09:56 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Legushka, никакой магии. мерджите до последнего (лимит) по неуникальному индексу, который (индекс) у вас префикс требуемой сортировки. + добираете из того же значения неуникального индекса все из той же лунки. (т.к. при ресорте с постфиксом они могут обогнать выбранное без оного последнее) + потом еще раз сортите результат, но с учетом унифицирующего постфикса требуемой сортировки. и обрезаете неудачников из той лунки, которую добирали. если у вас не этот случай (сортировка по листу, лидирующая часть которого совпадает с неуникальным индексом, и есть какой--то постфикс) -- то у вас не магия, а сапоги в смятку. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.09.2017, 11:31 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Maxim BogukРолг Хупинпропущено... вообще-то думается, что в таком случае результат объединения в общем случаем будет неправильный Обоснуйте? ;) Или приведите контрпример. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru не буду "не всегда" будет правильным. нет гарантии, что будет правильным ... |
|||
:
Нравится:
Не нравится:
|
|||
14.09.2017, 12:43 |
|
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
|
|||
---|---|---|---|
#18+
Ролг ХупинMaxim Bogukпропущено... Обоснуйте? ;) Или приведите контрпример. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru не буду "не всегда" будет правильным. нет гарантии, что будет правильным Приведите пример где оно МОЖЕТ теоретически дать неверный ответ. ;) Благо это самое стандартное преобразование для union all из тех что я знаю для ускорения. -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
14.09.2017, 13:01 |
|
|
start [/forum/topic.php?fid=53&fpage=66&tid=1996227]: |
0ms |
get settings: |
12ms |
get forum list: |
15ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
35ms |
get topic data: |
14ms |
get forum data: |
3ms |
get page messages: |
109ms |
get tp. blocked users: |
2ms |
others: | 12ms |
total: | 210ms |
0 / 0 |