powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
35 сообщений из 35, показаны все 2 страниц
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520028
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
размышления

есть подзапрос: объедены две выборки через union all
набор строк в подзапросе может достигать нескольких сотен тыс

на общий результат накладывается еще куча джоинов не увеличивающих и не уменьшающих общее количество row

нет возможности лимит и оффсет перенести в подзапрос, (к сожалению используемый движок не позволяет, limit всегда в конце запроса)

есть общая сортировка по дате (дата определяется в обоих частях подзапроса, но из разных источников)

лимитом отбирается стабильно максимум 10 строк, все зависит от пагинации

Можно ли в этом случае ускорить пагинацию, что бы не собирать все строки, или в текущем варианте бесполезно?
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520035
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Legushka,

что сказать то хотели, барин ?
что не умеет он лимит поверх аппенда внутрь оппендуемого вставлять ?
ну дык давно известно.

даже хуже -- добавляшь в ордер бай в конец уникализирующее поле -- и все с ис с лимитом вдоль скатывается в лимит после сорта всего (всего !) , блин, скана.

всё в ваших руках
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520040
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,
а есть какие нибудь методы как решить? в голову ничего не приходит
не хочется ковырять все записи что бы потом отобрать только 10
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520066
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Legushkaqwwq,
а есть какие нибудь методы как решить? в голову ничего не приходит
не хочется ковырять все записи что бы потом отобрать только 10

писать запросы руками и вставлять limit 10 в обе части union all
насколько поможет - не факт но это единственное куда вообще можно копать.
Что там позволяет или нет ваш движек - ваши проблемы, можно всегда запрос в хранимку засунуть если очень хочется.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520068
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520077
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk , да там лимит и офсет добавляется движком,
к сожалению движок нельзя переделать что бы он лимиты в указанноое место вставлял

а что если подзапрос вида union all
как нибудь развернуть на join'ах (cross join, full outer join)
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520085
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Legushka,

теоретиццки он может мердж--аппенд выполнить в одной связке с лимитом.
т.е. партиции при наличии во всех индексов того же порядка, что и внешний одербай к головной. (но только с точностью до буквы. взять по 10+ (Вычитать все узлы неуникального) и отресортить и опять отрезать 10 ( или (до)сортить первенца в процессе,, и обрезать вычитку из отстающих ..) -- вот это всё оно не умеет.

если вы научитесь сами руками фетчить всё, что юнайтите, позаписьно дёшево вдоль вашего порядка -- то можете сами вовремя астанавицца.

а увидеть, что внутренности юниона (шире -- аппенда) можно дёшево смёрджить с минимальным ресортом и оверфетчем, в общем случае оно не умеет.

а за пагинацию оффсетом таки руки отрывать бы надо бы. но вот всё у них так -- некому свистоперделки писать будет.
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520088
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
глянул на разницу планов если бы лимит и офсет отработал внутри подзапроса и снаружи
уже большой выигрышь на внешних join получается (всего 10 раз вместо 100k )
буду трясти разработчиков движка что бы реализовали возможность вставки лимита в любую часть запроса)
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520091
PgSQLanonymous3
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Legushkaглянул на разницу планов если бы лимит и офсет отработал внутри подзапроса и снаружи
уже большой выигрышь на внешних join получается (всего 10 раз вместо 100k )
буду трясти разработчиков движка что бы реализовали возможность вставки лимита в любую часть запроса)А покажите всё же пример с данными и запросом... может быть, что-то всё же можно будет сделать.
Это (LIMIT только "снаружи") у Вас единственное ограничение, кстати?
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520270
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukPS: в приличных местах за неограниченный (т.е не первые 5-10 страниц) paging через limit/offset - бьют по лицу (это крайне плохо заканчивается для базы, особенно весело когда приходит какой то тупой робот и начинает через limit/offset перебирать несколько миллионов страниц последовательно).
еще не делал пагинацию ни разу, как правильно реализовать если не через limit/offset, который присутствует в текущей версии?
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520279
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520291
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LegushkaMaxim Boguk , да там лимит и офсет добавляется движком,
к сожалению движок нельзя переделать что бы он лимиты в указанноое место вставлял

а что если подзапрос вида union all
как нибудь развернуть на join'ах (cross join, full outer join)
легко
full join + группировка и прекрасно заменяется
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520292
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
правда сомневаюсь что это тебе помоежет. Лимит все равно до джоина применяться не будет
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520488
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Постгрес может эффективно выполнить такой запрос - выбрав не все строки, а только нужные по лимиту. Важно, чтобы на каждой таблице существовал нужный индекс, чтобы не требовалось переупорядочивание строк. Тогда сможет использовать 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.
                                                                                                                                               QUERY PLAN                                                                                                                                                
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=8.30..489.06 rows=10 width=281) (actual time=0.296..0.890 rows=10 loops=1)
   ->  Nested Loop  (cost=8.30..633.29 rows=13 width=281) (actual time=0.296..0.889 rows=10 loops=1)
         ->  Nested Loop  (cost=8.30..558.59 rows=13 width=215) (actual time=0.273..0.778 rows=10 loops=1)
               ->  Nested Loop  (cost=8.30..515.82 rows=13 width=215) (actual time=0.267..0.744 rows=10 loops=1)
                     ->  Nested Loop  (cost=8.30..443.58 rows=13 width=186) (actual time=0.262..0.712 rows=10 loops=1)
                           ->  Nested Loop  (cost=8.30..370.06 rows=13 width=165) (actual time=0.244..0.646 rows=10 loops=1)
                                 ->  Nested Loop  (cost=8.30..358.32 rows=13 width=153) (actual time=0.226..0.563 rows=10 loops=1)
                                       ->  Nested Loop  (cost=8.30..330.43 rows=13 width=151) (actual time=0.189..0.347 rows=10 loops=1)
                                             ->  Nested Loop  (cost=8.30..258.27 rows=13 width=114) (actual time=0.178..0.293 rows=10 loops=1)
                                                   ->  Nested Loop  (cost=8.30..186.14 rows=13 width=90) (actual time=0.167..0.240 rows=10 loops=1)
                                                         ->  Merge Append  (cost=8.30..113.30 rows=13 width=74) (actual time=0.146..0.169 rows=10 loops=1)
                                                               Sort Key: usage.bytes_out DESC
                                                               ->  Index Scan Backward using usage_time_id_clienturi_parent_id_geo_id_useragent_id_backe_idx on usage  (cost=0.12..8.16 rows=1 width=74) (actual time=0.006..0.006 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_time_id_clienturi_parent_id_geo_id_useragent_id__idx on usage_2017  (cost=0.70..8.74 rows=1 width=74) (actual time=0.028..0.049 rows=10 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2016_time_id_clienturi_parent_id_geo_id_useragent_id__idx on usage_2016  (cost=0.70..8.74 rows=1 width=74) (actual time=0.011..0.011 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_04_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_04  (cost=0.71..8.75 rows=1 width=74) (actual time=0.010..0.010 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_03_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_03  (cost=0.71..8.74 rows=1 width=74) (actual time=0.010..0.010 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_06_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_06  (cost=0.71..8.75 rows=1 width=74) (actual time=0.011..0.011 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_05_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_05  (cost=0.71..8.75 rows=1 width=74) (actual time=0.009..0.009 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_02_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_02  (cost=0.71..8.74 rows=1 width=74) (actual time=0.011..0.011 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_01_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_01  (cost=0.71..8.74 rows=1 width=74) (actual time=0.010..0.010 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_07_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_07  (cost=0.71..8.75 rows=1 width=74) (actual time=0.012..0.012 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_08_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_08  (cost=0.71..8.75 rows=1 width=74) (actual time=0.012..0.012 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_09_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_09  (cost=0.71..8.74 rows=1 width
=74) (actual time=0.012..0.012 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 21
0) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                               ->  Index Scan Backward using usage_2017_10_time_id_clienturi_parent_id_geo_id_useragent__idx on usage_2017_10  (cost=0.15..8.19 rows=1 width=74) (actual time=0.002..0.002 rows=0 loops=1)
                                                                     Index Cond: ((time_id = 448540) AND (clienturi_parent_id = 649608573) AND (geo_id = 753) AND (useragent_id = 4176) AND (backend_id = 210) AND (proto_id = 67) AND (referrer_id = 11713775) AND (status_id = 1) AND (custom_id = 1))
                                                         ->  Limit  (cost=0.00..5.58 rows=1 width=20) (actual time=0.006..0.006 rows=1 loops=10)
                                                               ->  Result  (cost=0.00..16.75 rows=3 width=20) (actual time=0.006..0.006 rows=1 loops=10)
                                                                     ->  Append  (cost=0.00..16.75 rows=3 width=20) (actual time=0.005..0.005 rows=1 loops=10)
                                                                           ->  Seq Scan on "time"  (cost=0.00..0.00 rows=1 width=20) (actual time=0.000..0.000 rows=0 loops=10)
                                                                                 Filter: (id = usage.time_id)
                                                                           ->  Index Scan using time_2016_pkey on time_2016  (cost=0.42..8.44 rows=1 width=20) (actual time=0.002..0.002 rows=0 loops=10)
                                                                                 Index Cond: (id = usage.time_id)
                                                                           ->  Index Scan using time_2017_pkey on time_2017  (cost=0.29..8.31 rows=1 width=20) (actual time=0.002..0.002 rows=1 loops=10)
                                                                                 Index Cond: (id = usage.time_id)
                                                   ->  Limit  (cost=0.00..5.53 rows=1 width=26) (actual time=0.005..0.005 rows=1 loops=10)
                                                         ->  Result  (cost=0.00..16.59 rows=3 width=26) (actual time=0.005..0.005 rows=1 loops=10)
                                                               ->  Append  (cost=0.00..16.59 rows=3 width=26) (actual time=0.004..0.004 rows=1 loops=10)
                                                                     ->  Seq Scan on geo  (cost=0.00..0.00 rows=1 width=64) (actual time=0.000..0.000 rows=0 loops=10)
                                                                           Filter: (id = usage.geo_id)
                                                                     ->  Index Scan using geo_2016_pkey on geo_2016  (cost=0.28..8.29 rows=1 width=7) (actual time=0.001..0.001 rows=0 loops=10)
                                                                           Index Cond: (id = usage.geo_id)
                                                                     ->  Index Scan using geo_2017_pkey on geo_2017  (cost=0.28..8.29 rows=1 width=7) (actual time=0.002..0.002 rows=1 loops=10)
                                                                           Index Cond: (id = usage.geo_id)
                                             ->  Limit  (cost=0.00..5.53 rows=1 width=38) (actual time=0.005..0.005 rows=1 loops=10)
                                                   ->  Result  (cost=0.00..16.59 rows=3 width=38) (actual time=0.004..0.004 rows=1 loops=10)
                                                         ->  Append  (cost=0.00..16.59 rows=3 width=38) (actual time=0.004..0.004 rows=1 loops=10)
                                                               ->  Seq Scan on useragent  (cost=0.00..0.00 rows=1 width=64) (actual time=0.000..0.000 rows=0 loops=10)
                                                                     Filter: (id = usage.useragent_id)
                                                               ->  Index Scan using useragent_2016_pkey on useragent_2016  (cost=0.28..8.30 rows=1 width=31) (actual time=0.001..0.001 rows=0 loops=10)
                                                                     Index Cond: (id = usage.useragent_id)
                                                               ->  Index Scan using useragent_2017_pkey on useragent_2017  (cost=0.28..8.29 rows=1 width=20) (actual time=0.002..0.002 rows=1 loops=10)
                                                                     Index Cond: (id = usage.useragent_id)
                                       ->  Limit  (cost=0.00..2.12 rows=1 width=4) (actual time=0.021..0.021 rows=1 loops=10)
                                             ->  Result  (cost=0.00..6.38 rows=3 width=4) (actual time=0.021..0.021 rows=1 loops=10)
                                                   ->  Append  (cost=0.00..6.38 rows=3 width=4) (actual time=0.021..0.021 rows=1 loops=10)
                                                         ->  Seq Scan on backend  (cost=0.00..0.00 rows=1 width=4) (actual time=0.000..0.000 rows=0 loops=10)
                                                               Filter: (id = usage.backend_id)
                                                         ->  Seq Scan on backend_2016  (cost=0.00..3.43 rows=1 width=4) (actual time=0.016..0.016 rows=0 loops=10)
                                                               Filter: (id = usage.backend_id)
                                                               Rows Removed by Filter: 194
                                                         ->  Seq Scan on backend_2017  (cost=0.00..2.95 rows=1 width=4) (actual time=0.003..0.003 rows=1 loops=10)
                                                               Filter: (id = usage.backend_id)
                                 ->  Limit  (cost=0.00..0.88 rows=1 width=14) (actual time=0.008..0.008 rows=1 loops=10)
                                       ->  Result  (cost=0.00..2.65 rows=3 width=14) (actual time=0.007..0.007 rows=1 loops=10)
                                             ->  Append  (cost=0.00..2.65 rows=3 width=14) (actual time=0.007..0.007 rows=1 loops=10)
                                                   ->  Seq Scan on proto  (cost=0.00..0.00 rows=1 width=32) (actual time=0.000..0.000 rows=0 loops=10)
                                                         Filter: (id = usage.proto_id)
                                                   ->  Seq Scan on proto_2016  (cost=0.00..1.61 rows=1 width=4) (actual time=0.005..0.005 rows=0 loops=10)
                                                         Filter: (id = usage.proto_id)
                                                         Rows Removed by Filter: 49
                                                   ->  Seq Scan on proto_2017  (cost=0.00..1.04 rows=1 width=5) (actual time=0.001..0.001 rows=1 loops=10)
                                                         Filter: (id = usage.proto_id)
                           ->  Limit  (cost=0.00..5.64 rows=1 width=25) (actual time=0.006..0.006 rows=1 loops=10)
                                 ->  Result  (cost=0.00..16.91 rows=3 width=25) (actual time=0.006..0.006 rows=1 loops=10)
                                       ->  Append  (cost=0.00..16.91 rows=3 width=25) (actual time=0.006..0.006 rows=1 loops=10)
                                             ->  Seq Scan on referrer  (cost=0.00..0.00 rows=1 width=32) (actual time=0.000..0.000 rows=0 loops=10)
                                                   Filter: (id = usage.referrer_id)
                                             ->  Index Scan using referrer_2016_pkey on referrer_2016  (cost=0.43..8.45 rows=1 width=22) (actual time=0.002..0.002 rows=0 loops=10)
                                                   Index Cond: (id = usage.referrer_id)
                                             ->  Index Scan using referrer_2017_pkey on referrer_2017  (cost=0.43..8.45 rows=1 width=22) (actual time=0.003..0.003 rows=1 loops=10)
                                                   Index Cond: (id = usage.referrer_id)
                     ->  Limit  (cost=0.00..5.54 rows=1 width=33) (actual time=0.003..0.003 rows=1 loops=10)
                           ->  Result  (cost=0.00..16.61 rows=3 width=33) (actual time=0.002..0.002 rows=1 loops=10)
                                 ->  Append  (cost=0.00..16.61 rows=3 width=33) (actual time=0.002..0.002 rows=1 loops=10)
                                       ->  Seq Scan on custom  (cost=0.00..0.00 rows=1 width=32) (actual time=0.000..0.000 rows=0 loops=10)
                                             Filter: (id = usage.custom_id)
                                       ->  Index Scan using custom_2016_pkey on custom_2016  (cost=0.15..8.17 rows=1 width=32) (actual time=0.001..0.001 rows=1 loops=10)
                                             Index Cond: (id = usage.custom_id)
                                       ->  Index Scan using custom_2017_pkey on custom_2017  (cost=0.42..8.44 rows=1 width=36) (never executed)
                                             Index Cond: (id = usage.custom_id)
               ->  Limit  (cost=0.00..3.27 rows=1 width=2) (actual time=0.003..0.003 rows=1 loops=10)
                     ->  Result  (cost=0.00..9.81 rows=3 width=2) (actual time=0.003..0.003 rows=1 loops=10)
                           ->  Append  (cost=0.00..9.81 rows=3 width=2) (actual time=0.002..0.002 rows=1 loops=10)
                                 ->  Seq Scan on status  (cost=0.00..0.00 rows=1 width=2) (actual time=0.000..0.000 rows=0 loops=10)
                                       Filter: (id = usage.status_id)
                                 ->  Index Scan using status_2016_pkey on status_2016  (cost=0.15..8.17 rows=1 width=2) (actual time=0.001..0.001 rows=1 loops=10)
                                       Index Cond: (id = usage.status_id)
                                 ->  Seq Scan on status_2017  (cost=0.00..1.64 rows=1 width=2) (never executed)
                                       Filter: (id = usage.status_id)
         ->  Limit  (cost=0.00..5.73 rows=1 width=73) (actual time=0.010..0.010 rows=1 loops=10)
               ->  Result  (cost=0.00..17.18 rows=3 width=73) (actual time=0.010..0.010 rows=1 loops=10)
                     ->  Append  (cost=0.00..17.18 rows=3 width=73) (actual time=0.010..0.010 rows=1 loops=10)
                           ->  Seq Scan on clienturi  (cost=0.00..0.00 rows=1 width=68) (actual time=0.000..0.000 rows=0 loops=10)
                                 Filter: (id = usage.clienturi_id)
                           ->  Index Scan using clienturi_2016_pkey1 on clienturi_2016  (cost=0.57..8.59 rows=1 width=73) (actual time=0.002..0.002 rows=0 loops=10)
                                 Index Cond: (id = usage.clienturi_id)
                           ->  Index Scan using clienturi_2017_pkey on clienturi_2017  (cost=0.57..8.59 rows=1 width=79) (actual time=0.006..0.006 rows=1 loops=10)
                                 Index Cond: (id = usage.clienturi_id)
 Planning time: 4.237 ms
 Execution time: 1.592 ms
(123 строки)
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520571
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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

это в случае, если ид поста монотонная последовательность
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520574
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukLegushkaqwwq,
а есть какие нибудь методы как решить? в голову ничего не приходит
не хочется ковырять все записи что бы потом отобрать только 10

писать запросы руками и вставлять limit 10 в обе части union all
насколько поможет - не факт но это единственное куда вообще можно копать.
Что там позволяет или нет ваш движек - ваши проблемы, можно всегда запрос в хранимку засунуть если очень хочется.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

вообще-то думается, что в таком случае результат объединения в общем случаем будет неправильный
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520622
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ролг Хупинэто в случае, если ид поста монотонная последовательность
Это в любом случае для стабильно сортируемого множества. А для offset пагинации стабильная сортировка необходима тем более, поэтому применимо.
http://use-the-index-luke.com/sql/partial-results/fetch-next-page
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520682
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ролг ХупинMaxim Bogukпропущено...


писать запросы руками и вставлять limit 10 в обе части union all
насколько поможет - не факт но это единственное куда вообще можно копать.
Что там позволяет или нет ваш движек - ваши проблемы, можно всегда запрос в хранимку засунуть если очень хочется.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

вообще-то думается, что в таком случае результат объединения в общем случаем будет неправильный

Обоснуйте? ;)
Или приведите контрпример.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520721
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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.
SELECT part, t_id, fld
  FROM public.t_t
  order by 2
limit 10;
======================
'Limit  (cost=0.69..1.55 rows=10 width=11) (actual time=0.052..0.060 rows=10 loops=1)'
'  Output: t_t.part, t_t.t_id, t_t.fld'
'  Buffers: shared hit=7'
'  ->  Merge Append  (cost=0.69..86.08 rows=1001 width=11) (actual time=0.052..0.059 rows=10 loops=1)'
'        Sort Key: t_t.t_id'
'        Buffers: shared hit=7'
'        ->  Index Scan using t_t_pkey on public.t_t  (cost=0.12..8.14 rows=1 width=40) (actual time=0.003..0.003 rows=0 loops=1)'
'              Output: t_t.part, t_t.t_id, t_t.fld'
'              Buffers: shared hit=1'
'        ->  Index Scan using t_1_pkey on public.t_1  (cost=0.27..29.77 rows=500 width=11) (actual time=0.009..0.011 rows=5 loops=1)'
'              Output: t_1.part, t_1.t_id, t_1.fld'
'              Buffers: shared hit=3'
'        ->  Index Scan using t_2_pkey on public.t_2  (cost=0.27..29.77 rows=500 width=11) (actual time=0.008..0.008 rows=6 loops=1)'
'              Output: t_2.part, t_2.t_id, t_2.fld'
'              Buffers: shared hit=3'
'Planning time: 0.190 ms'
'Execution time: 0.093 ms'



или для честного юниона
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
SELECT part, t_id, fld
FROM public.t_1
UNION ALL
SELECT part, t_id, fld
FROM public.t_1
order by 2
limit 10;
----------------------------------
'Limit  (cost=0.56..1.27 rows=10 width=11) (actual time=0.040..0.048 rows=10 loops=1)'
'  Output: t_1.part, t_1.t_id, t_1.fld'
'  Buffers: shared hit=6'
'  ->  Merge Append  (cost=0.56..72.06 rows=1000 width=11) (actual time=0.039..0.046 rows=10 loops=1)'
'        Sort Key: t_1.t_id'
'        Buffers: shared hit=6'
'        ->  Index Scan using t_1_pkey on public.t_1  (cost=0.27..29.77 rows=500 width=11) (actual time=0.030..0.032 rows=6 loops=1)'
'              Output: t_1.part, t_1.t_id, t_1.fld'
'              Buffers: shared hit=3'
'        ->  Index Scan using t_1_pkey on public.t_1 t_1_1  (cost=0.27..29.77 rows=500 width=11) (actual time=0.007..0.009 rows=5 loops=1)'
'              Output: t_1_1.part, t_1_1.t_id, t_1_1.fld'
'              Buffers: shared hit=3'
'Planning time: 0.176 ms'
'Execution time: 0.080 ms'



но позорище в том ,что он не умеет "выбрать последний узел неуникального (в общем случае) индекса, на котором произошло насыщение лимита и отресортив еще раз лимитнутся". даже без аппенда.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
SELECT part, t_id, fld
FROM public.t_1
order by 2,1
limit 10;
------------------------
'Limit  (cost=18.80..18.83 rows=10 width=11) (actual time=0.180..0.183 rows=10 loops=1)'
'  Output: part, t_id, fld'
'  Buffers: shared hit=3'
'  ->  Sort  (cost=18.80..20.05 rows=500 width=11) (actual time=0.178..0.180 rows=10 loops=1)'
'        Output: part, t_id, fld'
'        Sort Key: t_1.t_id, t_1.part'
'        Sort Method: top-N heapsort  Memory: 25kB'
'        Buffers: shared hit=3'
'        ->  Seq Scan on public.t_1  (cost=0.00..8.00 rows=500 width=11) (actual time=0.016..0.088 rows=500 loops=1)'
'              Output: part, t_id, fld'
'              Buffers: shared hit=3'
'Planning time: 0.114 ms'
'Execution time: 0.211 ms'



я где-то давно тут показывал, как это обрезать ("без аппенда") скл-м.

(в процессе мердж оппенда с индексным префиксом и уникализирующем постфиксе в сортировке это делать, алгоритмически, не сложнее, если у тебя в руках seek, да даже на скл это пишется, в рекурсивеном т.с. стиле. хотя и немного лишнего. проще грубо взять по ломтю, и отресортив все выбросить.
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520765
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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.
SELECT * FROM t_t 
ORDER BY fld,t_id limit 30
-------------------------------------
Limit  (cost=9034.53..9034.61 rows=30 width=12) (actual time=95.907..95.916 rows=30 loops=1)
  Output: t_t.part, t_t.t_id, t_t.fld
  Buffers: shared hit=1088
  ->  Sort  (cost=9034.53..9537.04 rows=201003 width=12) (actual time=95.905..95.911 rows=30 loops=1)
        Output: t_t.part, t_t.t_id, t_t.fld
        Sort Key: t_t.fld, t_t.t_id
        Sort Method: top-N heapsort  Memory: 26kB
        Buffers: shared hit=1088
        ->  Append  (cost=0.00..3098.02 rows=201003 width=12) (actual time=0.010..48.808 rows=201002 loops=1)
              Buffers: shared hit=1088
              ->  Seq Scan on public.t_t  (cost=0.00..0.00 rows=1 width=40) (actual time=0.003..0.003 rows=0 loops=1)
                    Output: t_t.part, t_t.t_id, t_t.fld
              ->  Seq Scan on public.t_1  (cost=0.00..1549.02 rows=100502 width=12) (actual time=0.006..12.942 rows=100502 loops=1)
                    Output: t_1.part, t_1.t_id, t_1.fld
                    Buffers: shared hit=544
              ->  Seq Scan on public.t_2  (cost=0.00..1549.00 rows=100500 width=12) (actual time=0.007..10.542 rows=100500 loops=1)
                    Output: t_2.part, t_2.t_id, t_2.fld
                    Buffers: shared hit=544
Planning time: 0.205 ms
Execution time: 95.946 ms



и через мердж-аппенд с ресортом:
Код: 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.
SELECT * FROM (
SELECT * FROM t_t 

ORDER BY fld
LIMIT 30 +(SELECT count(1) FROM public.t_t  
	WHERE fld = (SELECT fld from (SELECT fld FROM public.t_t ORDER BY 1 LIMIT 30) last ORDER BY fld desc LIMIT 1)
			) --число последних значений неуникального. все сложнее (только в SQL) когда nullable, 
) buff
ORDER BY fld,t_id limit 30
----------------------------------------------------------------------------
Limit  (cost=2145.10..2145.18 rows=30 width=12) (actual time=0.918..0.932 rows=30 loops=1)
  Output: t_t.part, t_t.t_id, t_t.fld
  Buffers: shared hit=150
  ->  Sort  (cost=2145.10..2195.35 rows=20100 width=12) (actual time=0.917..0.923 rows=30 loops=1)
        Output: t_t.part, t_t.t_id, t_t.fld
        Sort Key: t_t.fld, t_t.t_id
        Sort Method: top-N heapsort  Memory: 26kB
        Buffers: shared hit=150
        ->  Limit  (cost=12.04..1350.46 rows=20100 width=12) (actual time=0.308..0.733 rows=132 loops=1)
              Output: t_t.part, t_t.t_id, t_t.fld
              Buffers: shared hit=150
              InitPlan 2 (returns $1)
                ->  Aggregate  (cost=11.30..11.31 rows=1 width=8) (actual time=0.273..0.273 rows=1 loops=1)
                      Output: count(1)
                      Buffers: shared hit=12
                      InitPlan 1 (returns $0)
                        ->  Limit  (cost=2.55..2.55 rows=1 width=4) (actual time=0.117..0.117 rows=1 loops=1)
                              Output: t_t_1.fld
                              Buffers: shared hit=7
                              ->  Sort  (cost=2.55..2.63 rows=30 width=4) (actual time=0.117..0.117 rows=1 loops=1)
                                    Output: t_t_1.fld
                                    Sort Key: t_t_1.fld DESC
                                    Sort Method: top-N heapsort  Memory: 25kB
                                    Buffers: shared hit=7
                                    ->  Limit  (cost=0.73..2.10 rows=30 width=4) (actual time=0.051..0.081 rows=30 loops=1)
                                          Output: t_t_1.fld
                                          Buffers: shared hit=7
                                          ->  Merge Append  (cost=0.73..9160.11 rows=201003 width=4) (actual time=0.051..0.073 rows=30 loops=1)
                                                Sort Key: t_t_1.fld
                                                Buffers: shared hit=7
                                                ->  Index Only Scan using t_t_fld_idx on public.t_t t_t_1  (cost=0.12..8.14 rows=1 width=32) (actual time=0.005..0.005 rows=0 loops=1)
                                                      Output: t_t_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=1
                                                ->  Index Only Scan using t_1_fld_idx on public.t_1 t_1_1  (cost=0.29..2747.82 rows=100502 width=4) (actual time=0.023..0.034 rows=30 loops=1)
                                                      Output: t_1_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=3
                                                ->  Index Only Scan using t_2_fld_idx on public.t_2 t_2_1  (cost=0.29..2715.79 rows=100500 width=4) (actual time=0.019..0.019 rows=1 loops=1)
                                                      Output: t_2_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=3
                      ->  Append  (cost=0.00..8.73 rows=9 width=0) (actual time=0.161..0.239 rows=102 loops=1)
                            Buffers: shared hit=12
                            ->  Seq Scan on public.t_t t_t_2  (cost=0.00..0.00 rows=1 width=0) (actual time=0.004..0.004 rows=0 loops=1)
                                  Filter: (t_t_2.fld = $0)
                            ->  Index Only Scan using t_1_fld_idx on public.t_1 t_1_2  (cost=0.29..4.36 rows=4 width=0) (actual time=0.156..0.188 rows=102 loops=1)
                                  Index Cond: (t_1_2.fld = $0)
                                  Heap Fetches: 0
                                  Buffers: shared hit=10
                            ->  Index Only Scan using t_2_fld_idx on public.t_2 t_2_2  (cost=0.29..4.36 rows=4 width=0) (actual time=0.021..0.021 rows=0 loops=1)
                                  Index Cond: (t_2_2.fld = $0)
                                  Heap Fetches: 0
                                  Buffers: shared hit=2
              ->  Merge Append  (cost=0.73..13385.08 rows=201003 width=12) (actual time=0.029..0.414 rows=132 loops=1)
                    Sort Key: t_t.fld
                    Buffers: shared hit=138
                    ->  Index Scan using t_t_fld_idx on public.t_t  (cost=0.12..8.14 rows=1 width=40) (actual time=0.002..0.002 rows=0 loops=1)
                          Output: t_t.part, t_t.t_id, t_t.fld
                          Buffers: shared hit=1
                    ->  Index Scan using t_1_fld_idx on public.t_1  (cost=0.29..4863.84 rows=100502 width=12) (actual time=0.013..0.221 rows=103 loops=1)
                          Output: t_1.part, t_1.t_id, t_1.fld
                          Buffers: shared hit=105
                    ->  Index Scan using t_2_fld_idx on public.t_2  (cost=0.29..4824.75 rows=100500 width=12) (actual time=0.011..0.103 rows=30 loops=1)
                          Output: t_2.part, t_2.t_id, t_2.fld
                          Buffers: shared hit=32
Planning time: 0.550 ms
Execution time: 1.149 ms



:
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520904
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq, это какая то магия, подставил свои таблицы в ваш пример
вот два плана
стандартная сортировка
https://explain.depesz.com/s/Rz2

и магия)
https://explain.depesz.com/s/oEhM

я в шоке)))
могли бы вы подробно рассказать что происходит на человеческом языке:
что это значит:
число последних значений неуникального. все сложнее (только в SQL) когда nullable

и есть ли подводные камни?
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39520988
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Legushka,

никакой магии. мерджите до последнего (лимит) по неуникальному индексу, который (индекс) у вас префикс требуемой сортировки.
+ добираете из того же значения неуникального индекса все из той же лунки.
(т.к. при ресорте с постфиксом они могут обогнать выбранное без оного последнее)
+ потом еще раз сортите результат, но с учетом унифицирующего постфикса требуемой сортировки. и обрезаете неудачников из той лунки, которую добирали.

если у вас не этот случай (сортировка по листу, лидирующая часть которого совпадает с неуникальным индексом, и есть какой--то постфикс) -- то у вас не магия, а сапоги в смятку.
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521047
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukРолг Хупинпропущено...


вообще-то думается, что в таком случае результат объединения в общем случаем будет неправильный

Обоснуйте? ;)
Или приведите контрпример.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

не буду

"не всегда" будет правильным.
нет гарантии, что будет правильным
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521061
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ролг ХупинMaxim Bogukпропущено...


Обоснуйте? ;)
Или приведите контрпример.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

не буду

"не всегда" будет правильным.
нет гарантии, что будет правильным

Приведите пример где оно МОЖЕТ теоретически дать неверный ответ. ;)
Благо это самое стандартное преобразование для union all из тех что я знаю для ускорения.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521087
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

А можете предоставить скрипты для вашей таблицы `t_t`? чтобы был самодостаточный демонстрационный пример?
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521111
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukРолг Хупинпропущено...


не буду

"не всегда" будет правильным.
нет гарантии, что будет правильным

Приведите пример где оно МОЖЕТ теоретически дать неверный ответ. ;)
Благо это самое стандартное преобразование для union all из тех что я знаю для ускорения.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

Ну, напримери, вы выше писали

1. писать запросы руками и вставлять limit 10 в обе части union all
2. затем приводили пример:
select * from
(select ...
LIMIT [offset+limit]
) UNION ALL
(select ...
LIMIT [offset+limit]
)
ORDER BY ...
OFFSET offset
LIMIT limit;

Например, если не будет одинаковой сортировки в подзапросах в этом случае возможно проявится проблема
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521153
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,
авторБлаго это самое стандартное преобразование для union all из тех что я знаю для ускорения.

приведите плиз пример как преобразовать UNION ALL ?
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521164
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ролг ХупинMaxim Bogukпропущено...


Приведите пример где оно МОЖЕТ теоретически дать неверный ответ. ;)
Благо это самое стандартное преобразование для union all из тех что я знаю для ускорения.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru

Ну, напримери, вы выше писали

1. писать запросы руками и вставлять limit 10 в обе части union all
2. затем приводили пример:
select * from
(select ...
LIMIT [offset+limit]
) UNION ALL
(select ...
LIMIT [offset+limit]
)
ORDER BY ...
OFFSET offset
LIMIT limit;

Например, если не будет одинаковой сортировки в подзапросах в этом случае возможно проявится проблема

А ORDER BY в подзапросах на что?

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521225
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vyegorovqwwq,

А можете предоставить скрипты для вашей таблицы `t_t`? чтобы был самодостаточный демонстрационный пример?
табличка модельная, отсюда :
20003776

добавлены индексы по fld на все партиции и головную. (без паттернопсов)
и вставлено дважды по 100000 поверх тех 1000, что было в. (итого -- по 100500 на партицию.) генератором серий.
// в fld ~ g % 500 ? кажется

если хотите всё в одном месте -- чуть позже соберу.
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521266
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukРолг Хупинпропущено...


Ну, напримери, вы выше писали

1. писать запросы руками и вставлять limit 10 в обе части union all
2. затем приводили пример:
select * from
(select ...
LIMIT [offset+limit]
) UNION ALL
(select ...
LIMIT [offset+limit]
)
ORDER BY ...
OFFSET offset
LIMIT limit;

Например, если не будет одинаковой сортировки в подзапросах в этом случае возможно проявится проблема

А ORDER BY в подзапросах на что?

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru


см. выше, вы о них не писали, вот и я сделал примечание.
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521385
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vyegorov,
из 19757774

create and data
Код: 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.
DROP TABLE if exists t_t  cascade;

CREATE TABLE t_t 
(part integer NOT NULL 
,t_id serial primary key
,fld text 
,CHECK (part is null ) no inherit 
);
CREATE INDEX ON t_t (fld);
CREATE TABLE t_1
(
LIKE t_t INCLUDING INDEXES
,CHECK (part =1 ) no inherit 
)
inherits (t_t)
;
CREATE TABLE t_2
(
LIKE t_t INCLUDING INDEXES
,CHECK (part = 2 ) no inherit 
)
inherits (t_t)
;
CREATE VIEW t AS select * from t_t;
ALTER TABLE t ALTER t_id SET DEFAULT nextval('t_t_t_id_seq'::regclass); -- удобства на улице

CREATE OR REPLACE FUNCTION part_insert_trigger()
RETURNS TRIGGER AS $body$
BEGIN
	IF (NEW.part= 1) THEN
		INSERT INTO t_1 VALUES (NEW.*);
	ELSIF (NEW.part = 2) THEN
		INSERT INTO t_2 VALUES (NEW.*);
	ELSE
		--RAISE EXCEPTION 'partition key is out of range.  Fix the trigger function';
		INSERT INTO t_t VALUES (NEW.*);
	END IF;
	RETURN NEW; -- RETURN NEW in this case, typically you'd return NULL from this trigger, but for views we return NEW
END;
$body$
LANGUAGE plpgsql;

CREATE TRIGGER ins
INSTEAD OF INSERT ON t
FOR EACH ROW EXECUTE PROCEDURE part_insert_trigger(); -- create "INSTEAD OF" trigger
---UPDATE---
CREATE OR REPLACE FUNCTION part_update_trigger()
RETURNS TRIGGER AS $body$
BEGIN
	
	IF (NEW.part= OLD.part) THEN
		UPDATE t_t SET	part	=NEW.part
				,t_id	=NEW.t_id
				,fld = 	NEW.fld
		WHERE 	
			t_t.part	=NEW.part
			AND t_t.t_id	=NEW.t_id;
	ELSE
		DELETE FROM t_t WHERE t_id = OLD.t_id;
		INSERT INTO t VALUES (NEW.*);
	END IF;
	RETURN NEW; -- RETURN NEW in this case, typically you'd return NULL from this trigger, but for views we return NEW
END;
$body$
LANGUAGE plpgsql;

CREATE TRIGGER upd
INSTEAD OF UPDATE ON t
FOR EACH ROW EXECUTE PROCEDURE part_update_trigger(); -- create "INSTEAD OF" trigger


INSERT INTO t (part,fld) SELECT  g%2+1 , chr(32 + g%500) FROM generate_series(1,201000) g;




merge append not nullable
if not nullable
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
SELECT * FROM (
SELECT * FROM t_t 

ORDER BY fld
LIMIT 30 +(SELECT count(1) FROM public.t_t  
	WHERE
		fld = (SELECT fld from (SELECT fld FROM public.t_t ORDER BY 1 LIMIT 30) last ORDER BY fld desc LIMIT 1)
		
	)
) buff
ORDER BY fld,t_id limit 30


Код: 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.
Limit  (cost=2188.53..2188.61 rows=30 width=10) (actual time=1.446..1.458 rows=30 loops=1)
  Output: t_t.part, t_t.t_id, t_t.fld
  Buffers: shared hit=452
  ->  Sort  (cost=2188.53..2238.78 rows=20100 width=10) (actual time=1.445..1.454 rows=30 loops=1)
        Output: t_t.part, t_t.t_id, t_t.fld
        Sort Key: t_t.fld, t_t.t_id
        Sort Method: top-N heapsort  Memory: 26kB
        Buffers: shared hit=452
        ->  Limit  (cost=35.97..1393.89 rows=20100 width=10) (actual time=0.379..1.109 rows=432 loops=1)
              Output: t_t.part, t_t.t_id, t_t.fld
              Buffers: shared hit=452
              InitPlan 2 (returns $1)
                ->  Aggregate  (cost=35.23..35.24 rows=1 width=8) (actual time=0.358..0.358 rows=1 loops=1)
                      Output: count(1)
                      Buffers: shared hit=13
                      InitPlan 1 (returns $0)
                        ->  Limit  (cost=2.56..2.56 rows=1 width=2) (actual time=0.084..0.084 rows=1 loops=1)
                              Output: t_t_1.fld
                              Buffers: shared hit=7
                              ->  Sort  (cost=2.56..2.64 rows=30 width=2) (actual time=0.084..0.084 rows=1 loops=1)
                                    Output: t_t_1.fld
                                    Sort Key: t_t_1.fld DESC
                                    Sort Method: top-N heapsort  Memory: 25kB
                                    Buffers: shared hit=7
                                    ->  Limit  (cost=0.73..2.11 rows=30 width=2) (actual time=0.047..0.066 rows=30 loops=1)
                                          Output: t_t_1.fld
                                          Buffers: shared hit=7
                                          ->  Merge Append  (cost=0.73..9228.04 rows=201001 width=2) (actual time=0.046..0.062 rows=30 loops=1)
                                                Sort Key: t_t_1.fld
                                                Buffers: shared hit=7
                                                ->  Index Only Scan using t_t_fld_idx on public.t_t t_t_1  (cost=0.12..8.14 rows=1 width=32) (actual time=0.003..0.003 rows=0 loops=1)
                                                      Output: t_t_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=1
                                                ->  Index Only Scan using t_1_fld_idx on public.t_1 t_1_1  (cost=0.29..2755.79 rows=100500 width=2) (actual time=0.019..0.023 rows=30 loops=1)
                                                      Output: t_1_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=3
                                                ->  Index Only Scan using t_2_fld_idx on public.t_2 t_2_1  (cost=0.29..2775.79 rows=100500 width=2) (actual time=0.018..0.018 rows=1 loops=1)
                                                      Output: t_2_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=3
                      ->  Append  (cost=0.00..30.66 rows=805 width=0) (actual time=0.135..0.294 rows=402 loops=1)
                            Buffers: shared hit=13
                            ->  Seq Scan on public.t_t t_t_2  (cost=0.00..0.00 rows=1 width=0) (actual time=0.003..0.003 rows=0 loops=1)
                                  Filter: (t_t_2.fld = $0)
                            ->  Index Only Scan using t_1_fld_idx on public.t_1 t_1_2  (cost=0.29..15.33 rows=402 width=0) (actual time=0.132..0.214 rows=402 loops=1)
                                  Index Cond: (t_1_2.fld = $0)
                                  Heap Fetches: 0
                                  Buffers: shared hit=11
                            ->  Index Only Scan using t_2_fld_idx on public.t_2 t_2_2  (cost=0.29..15.33 rows=402 width=0) (actual time=0.015..0.015 rows=0 loops=1)
                                  Index Cond: (t_2_2.fld = $0)
                                  Heap Fetches: 0
                                  Buffers: shared hit=2
              ->  Merge Append  (cost=0.73..13579.97 rows=201001 width=10) (actual time=0.018..0.686 rows=432 loops=1)
                    Sort Key: t_t.fld
                    Buffers: shared hit=439
                    ->  Index Scan using t_t_fld_idx on public.t_t  (cost=0.12..8.14 rows=1 width=40) (actual time=0.002..0.002 rows=0 loops=1)
                          Output: t_t.part, t_t.t_id, t_t.fld
                          Buffers: shared hit=1
                    ->  Index Scan using t_1_fld_idx on public.t_1  (cost=0.29..4931.73 rows=100500 width=10) (actual time=0.007..0.520 rows=432 loops=1)
                          Output: t_1.part, t_1.t_id, t_1.fld
                          Buffers: shared hit=435
                    ->  Index Scan using t_2_fld_idx on public.t_2  (cost=0.29..4951.78 rows=100500 width=10) (actual time=0.007..0.007 rows=1 loops=1)
                          Output: t_2.part, t_2.t_id, t_2.fld
                          Buffers: shared hit=3
Planning time: 0.544 ms
Execution time: 1.611 ms





merge append nullable
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
SELECT * FROM (
SELECT * FROM t_t 

ORDER BY fld
LIMIT 30 +(SELECT count(1) FROM public.t_t  
	WHERE
		fld = (SELECT fld from (SELECT fld FROM public.t_t ORDER BY 1 LIMIT 30) last ORDER BY fld desc LIMIT 1)
		OR ( fld IS NULL AND (SELECT fld from (SELECT fld FROM public.t_t ORDER BY 1 LIMIT 30) last ORDER BY fld desc LIMIT 1)
			IS NULL
		)
	)
) buff
ORDER BY fld,t_id limit 30


Код: 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.
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.
Limit  (cost=3257.31..3257.39 rows=30 width=10) (actual time=2.171..2.178 rows=30 loops=1)
  Output: t_t.part, t_t.t_id, t_t.fld
  Buffers: shared hit=857
  ->  Sort  (cost=3257.31..3307.56 rows=20100 width=10) (actual time=2.169..2.173 rows=30 loops=1)
        Output: t_t.part, t_t.t_id, t_t.fld
        Sort Key: t_t.fld, t_t.t_id
        Sort Method: top-N heapsort  Memory: 26kB
        Buffers: shared hit=857
        ->  Limit  (cost=1104.75..2462.67 rows=20100 width=10) (actual time=1.199..1.804 rows=432 loops=1)
              Output: t_t.part, t_t.t_id, t_t.fld
              Buffers: shared hit=857
              InitPlan 3 (returns $2)
                ->  Aggregate  (cost=1104.01..1104.02 rows=1 width=8) (actual time=1.177..1.178 rows=1 loops=1)
                      Output: count(1)
                      Buffers: shared hit=418
                      InitPlan 1 (returns $0)
                        ->  Limit  (cost=2.56..2.56 rows=1 width=2) (actual time=0.094..0.094 rows=1 loops=1)
                              Output: t_t_1.fld
                              Buffers: shared hit=7
                              ->  Sort  (cost=2.56..2.64 rows=30 width=2) (actual time=0.093..0.093 rows=1 loops=1)
                                    Output: t_t_1.fld
                                    Sort Key: t_t_1.fld DESC
                                    Sort Method: top-N heapsort  Memory: 25kB
                                    Buffers: shared hit=7
                                    ->  Limit  (cost=0.73..2.11 rows=30 width=2) (actual time=0.052..0.071 rows=30 loops=1)
                                          Output: t_t_1.fld
                                          Buffers: shared hit=7
                                          ->  Merge Append  (cost=0.73..9228.04 rows=201001 width=2) (actual time=0.052..0.066 rows=30 loops=1)
                                                Sort Key: t_t_1.fld
                                                Buffers: shared hit=7
                                                ->  Index Only Scan using t_t_fld_idx on public.t_t t_t_1  (cost=0.12..8.14 rows=1 width=32) (actual time=0.003..0.003 rows=0 loops=1)
                                                      Output: t_t_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=1
                                                ->  Index Only Scan using t_1_fld_idx on public.t_1 t_1_1  (cost=0.29..2755.79 rows=100500 width=2) (actual time=0.023..0.028 rows=30 loops=1)
                                                      Output: t_1_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=3
                                                ->  Index Only Scan using t_2_fld_idx on public.t_2 t_2_1  (cost=0.29..2775.79 rows=100500 width=2) (actual time=0.020..0.020 rows=1 loops=1)
                                                      Output: t_2_1.fld
                                                      Heap Fetches: 0
                                                      Buffers: shared hit=3
                      InitPlan 2 (returns $1)
                        ->  Limit  (cost=2.56..2.56 rows=1 width=2) (never executed)
                              Output: t_t_2.fld
                              ->  Sort  (cost=2.56..2.64 rows=30 width=2) (never executed)
                                    Output: t_t_2.fld
                                    Sort Key: t_t_2.fld DESC
                                    ->  Limit  (cost=0.73..2.11 rows=30 width=2) (never executed)
                                          Output: t_t_2.fld
                                          ->  Merge Append  (cost=0.73..9228.04 rows=201001 width=2) (never executed)
                                                Sort Key: t_t_2.fld
                                                ->  Index Only Scan using t_t_fld_idx on public.t_t t_t_2  (cost=0.12..8.14 rows=1 width=32) (never executed)
                                                      Output: t_t_2.fld
                                                      Heap Fetches: 0
                                                ->  Index Only Scan using t_1_fld_idx on public.t_1 t_1_2  (cost=0.29..2755.79 rows=100500 width=2) (never executed)
                                                      Output: t_1_2.fld
                                                      Heap Fetches: 0
                                                ->  Index Only Scan using t_2_fld_idx on public.t_2 t_2_2  (cost=0.29..2775.79 rows=100500 width=2) (never executed)
                                                      Output: t_2_2.fld
                                                      Heap Fetches: 0
                      ->  Append  (cost=0.00..1096.87 rows=805 width=0) (actual time=0.314..1.095 rows=402 loops=1)
                            Buffers: shared hit=418
                            ->  Seq Scan on public.t_t t_t_3  (cost=0.00..0.00 rows=1 width=0) (actual time=0.002..0.002 rows=0 loops=1)
                                  Filter: ((t_t_3.fld = $0) OR ((t_t_3.fld IS NULL) AND ($1 IS NULL)))
                            ->  Bitmap Heap Scan on public.t_1 t_1_3  (cost=15.81..548.43 rows=402 width=0) (actual time=0.311..0.996 rows=402 loops=1)
                                  Recheck Cond: ((t_1_3.fld = $0) OR (t_1_3.fld IS NULL))
                                  Filter: ((t_1_3.fld = $0) OR ((t_1_3.fld IS NULL) AND ($1 IS NULL)))
                                  Heap Blocks: exact=402
                                  Buffers: shared hit=414
                                  ->  BitmapOr  (cost=15.81..15.81 rows=402 width=0) (actual time=0.226..0.226 rows=0 loops=1)
                                        Buffers: shared hit=12
                                        ->  Bitmap Index Scan on t_1_fld_idx  (cost=0.00..11.31 rows=402 width=0) (actual time=0.221..0.221 rows=402 loops=1)
                                              Index Cond: (t_1_3.fld = $0)
                                              Buffers: shared hit=10
                                        ->  Bitmap Index Scan on t_1_fld_idx  (cost=0.00..4.30 rows=1 width=0) (actual time=0.003..0.003 rows=0 loops=1)
                                              Index Cond: (t_1_3.fld IS NULL)
                                              Buffers: shared hit=2
                            ->  Bitmap Heap Scan on public.t_2 t_2_3  (cost=15.81..548.43 rows=402 width=0) (actual time=0.022..0.022 rows=0 loops=1)
                                  Recheck Cond: ((t_2_3.fld = $0) OR (t_2_3.fld IS NULL))
                                  Filter: ((t_2_3.fld = $0) OR ((t_2_3.fld IS NULL) AND ($1 IS NULL)))
                                  Buffers: shared hit=4
                                  ->  BitmapOr  (cost=15.81..15.81 rows=402 width=0) (actual time=0.021..0.021 rows=0 loops=1)
                                        Buffers: shared hit=4
                                        ->  Bitmap Index Scan on t_2_fld_idx  (cost=0.00..11.31 rows=402 width=0) (actual time=0.018..0.018 rows=0 loops=1)
                                              Index Cond: (t_2_3.fld = $0)
                                              Buffers: shared hit=2
                                        ->  Bitmap Index Scan on t_2_fld_idx  (cost=0.00..4.30 rows=1 width=0) (actual time=0.003..0.003 rows=0 loops=1)
                                              Index Cond: (t_2_3.fld IS NULL)
                                              Buffers: shared hit=2
              ->  Merge Append  (cost=0.73..13579.97 rows=201001 width=10) (actual time=0.017..0.557 rows=432 loops=1)
                    Sort Key: t_t.fld
                    Buffers: shared hit=439
                    ->  Index Scan using t_t_fld_idx on public.t_t  (cost=0.12..8.14 rows=1 width=40) (actual time=0.001..0.001 rows=0 loops=1)
                          Output: t_t.part, t_t.t_id, t_t.fld
                          Buffers: shared hit=1
                    ->  Index Scan using t_1_fld_idx on public.t_1  (cost=0.29..4931.73 rows=100500 width=10) (actual time=0.007..0.387 rows=432 loops=1)
                          Output: t_1.part, t_1.t_id, t_1.fld
                          Buffers: shared hit=435
                    ->  Index Scan using t_2_fld_idx on public.t_2  (cost=0.29..4951.78 rows=100500 width=10) (actual time=0.007..0.007 rows=1 loops=1)
                          Output: t_2.part, t_2.t_id, t_2.fld
                          Buffers: shared hit=3
Planning time: 0.838 ms
Execution time: 2.412 ms





и тд.
можно случай лягушки префикс сорта == префиксу инд-а
или составной nullable префикс сорта == индексу расписать
всё так же
сильно не хватает операторов сравнения в смысле отношения порядка при сортировке
для упрощения записи сравнения. (симметричного "IS" вместо = и т.п.)
"IS DISTINCT FROM" не оператор.
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521392
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

Очень полезный пост, спасибо!
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521402
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

"Хм! Грех невелик, зато мудрость какова!"

PS: Действительно интересное решение. Более того пригодное для использования не для партиционирования а для ускорения запросов с ORDER BY a,b при наличии индекса только по а. Записал себе в копилку.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521545
Фотография Legushka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,qwwq
авторДействительно интересное решение. ORDER BY a,b при наличии индекса только по а. Записал себе в копилку.
тоже записал в копилку

кстати решение полезно если даже есть индекс a,b
а сортировку надо такую a desc, b или а, b desc
только остается разобраться как desc сортировку использовать в способе qwwq -)
...
Рейтинг: 0 / 0
оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
    #39521557
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Legushka,

это всё работа планировщика
то что такую алгоритмическую мелочь приходится писать руками -- показатель "продвинутости" планировщика
а для хенджоба и ручечек наружу торчит маловато, не говоря о пресловутых "текстпаттернопсах", у которых теоретически внутри порядок свой (отличный от) есть, но наружу его не отдадут. козлы
...
Рейтинг: 0 / 0
35 сообщений из 35, показаны все 2 страниц
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / оптимизация limit по union all (когда лимит нельзя перенести в подзапрос)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]