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

Yaroslav @chAlx314 Как было замечено RhodiumToad из IRC:

I suspect something's stopping the planner from being able to
deduce that (t.o).id is safe to push through a GROUP BY ocd.o

that might be fixable by making it a separate column of its own

Поэтому было создано дополнительно поле order_id из (level0.o).id
SELECT * FROM (
SELECT
sum( level1.group_suma ) OVER( PARTITION BY level1.order_id ) AS total_suma,
*
FROM (
SELECT
sum( level0.item_suma ) AS group_suma,
level0.o,
(level0.o).id as order_id
FROM order_cost_details() level0
GROUP BY level0.o, (level0.o).id, (level0.ic).consumed_period
) level1
) level2
WHERE level2.order_id = 6154 -- works fast
WHERE (level2.o).id = 6154 -- works slow
Как было указано в [ответе на SO](https://stackoverflow.com/a/57004652/4632019)

новое поле решает проблему и планер может использовать значение 6154
для оптимизации.

Но проблема заключается в том, что этот трюк работает только для order_id
В других ситуация мне нужно фильтровать мой набор по agreement_id.
Я переписал запрос:
SELECT * FROM (
SELECT
sum( level1.group_suma ) OVER( PARTITION BY level1.order_id ) AS total_suma,
fn() as new_field
*,
FROM (
SELECT
sum( level0.item_suma ) AS group_suma,
level0.o,
(level0.o).id as order_id
(level0.o).agreement_id as agreement_id
FROM order_cost_details() level0
GROUP BY level0.o, (level0.o).id, (level0.ic).consumed_period
) level1
) level2
WHERE level2.agreement_id = 6154 -- works fast
Получается, что если я хочу, чтобы планер использовал значение в оптимизации,
то я должен выбирать необходимые поля явным образом, пока, со временем,
просто напрасто перечислю их всех.

Но зачем это делать, если я и так передаю все поля по ссылке:

level0.o в результате даёт одно поле, которое содержит остальные

Таким образом поле (level2.o).id и (level0.o).id - это одно и тоже значение в памяти,
грубо говоря - алиас.

Поэтому если я явно обращаюсь к level0, почему PG запрещает мне это делать?

Я совершенно не против ситуации, когда PG может запретить push для новых
полей, которые были созданы в этом уровне, как например:

(level0.o).agreement_id as order_id

Вот есть наши 3 запроса (см. картинку). level0 - исходные данные
и level1, level2 - полученные (derived) данные.
Соответсвенно мы не может делать какие либо манипуляции (например фильтровать)
на level0, если эти данные у нас появились только на level1

В моём примере, если я напишу level2.new_field = 3,
то планер может запросто переписать его на level1.new_field. Это безопасно.
планер не может переписать его на level0.new_field,
т.к. на level0 этого поля нет.

Аналогично: level2.order_id -> level1.order_id. Это безопасно.
планер может переписать его на (level0.o).id,
т.к. на level0 это поле есть и (level0.o).id удовлетворяет условию группировки. (GROUP BY)

Я бы предложил рассматривать эти примеры не как push, а как bubbling.

тогда наше поле id всплывает вот так: id -> order_id -> order_id

А теперь по поводу ссылок. Наше о всплывает так: o -> o -> o
На всех уровнях - это одно и тоже о. Значит если я говорю:

o.id = 6154 или какое либо другие поля по ссылке (я имею ввиду o)

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

2 ответов

8 просмотров

Я Вам уже писал — Вы пишете "простыни", которые очень трудно для чего-то использовать! ;( Т.е. используя то, что Вы написали, воспроизвести проблему никто, кроме Вас, не может. Давайте minimal test case, потому что иначе вряд ли это кому-то (влкючая -hackers) будет интересно, понимаете?

Подозреваю, что запор происходит в процессе группировки: она по .o, а .o.id - это уже не значение, а вычисляемое поле. Должно ли так быть и может ли так не быть в общем случае, не знаю. Но поддержу идею, что для разборок необходим компактный тестовый пример с данными. Рекомендую выложить его на dbfiddle.uk, чтобы сразу были видны результаты запросов и можно было поиграть с параметрами.

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

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

Вопрос по диагностике ошибок (я знаю в чем, в данном конкретном примере, я знаю, как исправить, пример модельный, понятно, что в реальности бывает намного запутаннее). module...
ⰄⰎⰋⰐⰐⰑⰛⰤⰧⰧⰩⰄ ⰊⰑⰁⰓⰡⰛⰦⰕⰫ
10
А чем вам питонисты не угодили?😂
.
79
Есть какой-нибудь для Delphi/FPC T*Compression(Decompression)Stream на базе LZ4/Zstd/любой другой быстрый(и хорошо сжимающий) алгоритм А ещё лучше в pure pascal А ещё лучше од...
notme
48
Есть предложения, как подобное можно упростить?
Hemul GM
12
type TObj = object procedure Init; virtual; end; TObj1 = object(TObj) procedure Init; override; end; procedure TObj1.Init; begin inherited; end; procedur...
Alexander 👋
29
У меня вопросик назрел. Почему, создав класс без наследования и реализации деструктора Destroy, деструктор не вызывался при free. Потом указал наследование от tobject и overri...
Сергей Бычков
9
@y0zhig @shizzard А можно я опишу цель и может вообще ерланг мне не подходит. На текущий момент как я понимаю у ерланга есть легковесные потоки и задача выполняется в каком т...
Дмитрий Спиридонов
5
Всем привет, написал код ниже, но он выдает сегфолт, в чем причина? #include <stdio.h> #include <stdlib.h> #include <string.h> struct product { char *name; float price; };...
buzz базз
86
Такой вопросец - есть функция function MySuperDuperConcat(const a: array of AnsiString): AnsiString; Как мне в её теле сделать вот так? Result:=Concat(a); А не грустный вариан...
notme
15
just use free version ?? pycharm has a free version
Fan / Ac
9
Карта сайта