172 похожих чатов

Вопрос вроде популярный, но не смог найти ошибку в решении.

Нужно вытащить последнюю реинкарнацию организации - с максимальной org_version для данной org_id Почему postgres настолько ошибается в оценках и как сделать чтоб не ошибался?
rdb=# \d tt
Table "public.tt"
Column | Type | Collation | Nullable | Default
-------------+---------+-----------+----------+---------
org_id | integer | | |
org_version | integer | | |
Indexes:
"tt_id_version" btree (org_id, org_version)

rdb=#
rdb=# explain (buffers,analyze)
select * from tt d1,
(select org.org_id,
max(org.org_version) AS max_org_version
FROM tt org
WHERE org.org_id >= 0 GROUP by org.org_id) d2
where d1.org_id = d2.org_id and d1.org_version = d2.max_org_version;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=56.28..80.23 rows=6 width=16) (actual time=0.609..0.869 rows=847 loops=1)
Hash Cond: ((d1.org_id = org.org_id) AND (d1.org_version = (max(org.org_version))))
Buffers: shared hit=12
-> Seq Scan on tt d1 (cost=0.00..17.77 rows=1177 width=8) (actual time=0.012..0.074 rows=1177 loops=1)
Buffers: shared hit=6
-> Hash (cost=43.56..43.56 rows=848 width=8) (actual time=0.587..0.588 rows=847 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 42kB
Buffers: shared hit=6
-> HashAggregate (cost=26.60..35.08 rows=848 width=8) (actual time=0.391..0.485 rows=847 loops=1)
Group Key: org.org_id
Batches: 1 Memory Usage: 169kB
Buffers: shared hit=6
-> Seq Scan on tt org (cost=0.00..20.71 rows=1177 width=8) (actual time=0.007..0.128 rows=1176 loops=1)
Filter: (org_id >= 0)
Rows Removed by Filter: 1
Buffers: shared hit=6
Planning:
Buffers: shared hit=3
Planning Time: 0.352 ms
Execution Time: 0.959 ms
(20 rows)

rdb=#

17 ответов

40 просмотров

И Вы нашли для этого один из наихудших способов. ;( Почему бы не попробовать что-то получше (LATERAL, если есть таблица организаций; loose index scan (rCTE) или DISTINCT ON, если нет)? И, кстати, что б ему и не ошибаться в этом случае (в таблице даже ни одного ключа нет)? ;)

Sergey-Gr Автор вопроса
Yaroslav Schekin
И Вы нашли для этого один из наихудших способов. ;...

Я вот эти все извращения не очень понимаю. Но даже если сделать уникальный индекс на оба поля - всё равно ошибается. Надо объявить его как Primary Key?

Sergey Gr
Я вот эти все извращения не очень понимаю. Но даже...

Не понимаете — сидите с [в среднем так бывает] производительностью на два порядка (или более) худшей, чем могла бы быть — дело Ваше. ;( > всё равно ошибается. А ANALYZE выполняли? И вообще, это план на реальных данных (иначе обсуждать это я практического смысла не вижу)?

Sergey-Gr Автор вопроса
Yaroslav Schekin
Не понимаете — сидите с [в среднем так бывает] пр...

В реальности таблица шире, число строк точное. Analyze делал

Sergey Gr
В реальности таблица шире, число строк точное. Ana...

Тогда нужно копаться с конкретными данными и смотреть, как планировщик оценивает этот JOIN (но "чудо" там вряд ли будет — подобные оценки в принципе довольно грубы)...

Yaroslav Schekin
И Вы нашли для этого один из наихудших способов. ;...

А, собственно, почему? По-моему, как в его случае (когда org_version в среднем не сильно большэ одного на org_id) -- вменяемый довольно способ. Хотя, конечно... Планировщик за такое спасибо не скажэт.

Зачем для каждой организации свой счетчик, можно же сделать один на всех и брать его max + фильтр по org_id?

Ilya Anfimov
А, собственно, почему? По-моему, как в его случае...

Потому что объективные измерения (benchmarks) альтернативных способов (даже для разных распределений данных) показывают, что это так — погуглите или попробуйте.

Кстати, если чаще всего нужэн максимальный org_version -- то имеет смысл начинать с создания индэкса (org_id, org_version DESC) Чуть-чуть быстрее будут типичные операцыи и чуть-чуть лояльнее к нему отнесётся планировщик.

Yaroslav Schekin
Не понимаете — сидите с [в среднем так бывает] пр...

Да на какие два порядка, не будет там 10мкс на 1000 строк хоть обпишысь...

Yaroslav Schekin
И Вы нашли для этого один из наихудших способов. ;...

Кстати, я правильно помню, что самый поддержываемый синтаксисом DISTINCT ON -- до сих пор не умеет index skip scan?

Yaroslav Schekin
И Вы нашли для этого один из наихудших способов. ;...

И, в итоге, самый быстрый результат таких запросов -- пишэтся через WITH RECURSIVE ? (Но и то -- не за счёт того, что планировщик там что-то понимает, а как раз наоборот).

Ilya Anfimov
Да на какие два порядка, не будет там 10мкс на 100...

Где я говорил именно про 1000 строк?! Я написал "в среднем так бывает", безотносительно к конкретному примеру (я вообще подумал, что это просто тестовые данные / демонстрация).

Ilya Anfimov
Кстати, я правильно помню, что самый поддержываемы...

Так такого executor node до сих пор не существует — как он может его "уметь"? ;(

Ilya Anfimov
И, в итоге, самый быстрый результат таких запросов...

Самый быстрый (в норме) — LATERAL (или DISTINCT ON, если на каждое значение... org_id, в этом случае, приходится только 2-3 rows).

Ну, мало ли... На WITH RECURSIVE разложыть, например... Да и вообще. Есть многое на свете, друг Горацый, что мне лично и не снилось.

Ilya Anfimov
Ну, мало ли... На WITH RECURSIVE разложыть, наприм...

Не, все ждут, пока https://wiki.postgresql.org/wiki/Loose_indexscan кто-то "честно" реализует, зачем нам полумеры? ;)

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
вы делали что-то подобное и как? может есть либы готовые? увидел картинку нокода, где всё линиями соединено и стало интересно попробовать то же в ddl на lua сделать. решил с ч...
Victor
8
Подскажите пожалуйста, как в CustomDrawCell(Sender: TcxCustomGridTableView; ACanvas: TcxCanvas; AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean); получить наз...
A Z
7
Ребят в СИ можно реализовать ООП?
Николай
33
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
1
Он в одиночку это дело запилил или была какая-то команда?
Aquinary
12
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Всем привет, нужна как никогда, нужна помощь с IO в загрузчике. Пишу в code16 после установки сегментных регистров, пишу вывод символа. Пробовал 2 варианта: # 1 mov $0x0E, %a...
Shadow Akira
14
Карта сайта