|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
Пришлось решать одноразовую задачу. Таблица, содержащая группы записей по некоему полю. Группы подвергались обработке, в итоге получался набор записей той же структуры, но с модифицированными данными (в т.ч. с изменением количества записей в группе). Итоговые данные должны были лечь на место исходных. Задача была решена запросом, схематически выглядящим так: Код: sql 1. 2. 3.
Итоговый результат - правильный. Однако возник вопрос - гарантируется ли правильное выполнение подобной схемы? Действительно ли выполнение запроса идёт так: сперва полное выполнение cte1 и кэширование окончательного результата, затем очистка таблицы, затем копирование кэшированного результата в таблицу? Или возможна такая неприятность, что будет кэширован результат со ссылками на исходные записи, а не со значениями, и в результате часть данных будет утрачена? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2019, 16:46 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
AkinaИли возможна такая неприятность, что будет кэширован результат со ссылками на исходные записи, а не со значениями, и в результате часть данных будет утрачена? Такая ситуация невозможна: https://postgrespro.ru/docs/postgresql/11/queries-with#QUERIES-WITH-MODIFYING Важно понимать, что временная таблица, которую можно будет использовать в остальном запросе, создаётся из результата RETURNING, а не целевой таблицы оператора. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2019, 17:25 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
AkinaПришлось решать одноразовую задачу. Таблица, содержащая группы записей по некоему полю. Группы подвергались обработке, в итоге получался набор записей той же структуры, но с модифицированными данными (в т.ч. с изменением количества записей в группе). Итоговые данные должны были лечь на место исходных. Задача была решена запросом, схематически выглядящим так: Код: sql 1. 2. 3.
Итоговый результат - правильный. Однако возник вопрос - гарантируется ли правильное выполнение подобной схемы? Действительно ли выполнение запроса идёт так: сперва полное выполнение cte1 и кэширование окончательного результата, затем очистка таблицы, затем копирование кэшированного результата в таблицу? Или возможна такая неприятность, что будет кэширован результат со ссылками на исходные записи, а не со значениями, и в результате часть данных будет утрачена? думаецца, что записи, закомиченные инсертами других сессий между снапшотом КТЕ и началом делета, удалены не будут. по поводу коммита апдейта в этом же интервале слету не скажу. надо проверить, в какой момент делет в кте лочит записи. кажется, что должен на момент снепшота кте (даже при рид--коммитеде). т.е . другие коммитеры, пришедшие за данными удаляемых строк после снепшота кте, должны встать в очередь (и не увидеть их после делета). хотя можно для уверенности сразу залочить все записи тейблы for update в первом стейтменте кте. т.е., на деле, поменять порядок на делет--ретурненг, расчет результатов по содержанию возврата, и вставку резалта расчетов взад. а потом то же попытаться провернуть ротацией партиций с заменой делета на транкейт -- когда записей совсем много. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2019, 17:48 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
Akina, недавно искал похожую тему, у нас в функциях с WITH используются операции DELETE и UPDATE. По ссылке что давали раньше, есть такая фразейка: postgresproВложенные операторы в WITH выполняются одновременно друг с другом и с основным запросом. Таким образом, порядок, в котором операторы в WITH будут фактически изменять данные, непредсказуем. Все эти операторы выполняются с одним снимком данных (см. Главу 13), так что они не могут «видеть», как каждый из них меняет целевые таблицы. Это уменьшает эффект непредсказуемости фактического порядка изменения строк и означает, что RETURNING — единственный вариант передачи изменений от вложенных операторов WITH основному запросу Итого, как я понял, запросы в WITH выполняются параллельно (в случайном порядке). И если произойдёт выполнение cte2 раньше, то cte1 всё равно будет видеть данные, т.к. он использует данные из снимка. Но чтобы правильный результат показать в SELECT * FROM cte1, нужно добавить обязательнго RETURNING * ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2019, 18:08 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
VSVLADИтого, как я понял, запросы в WITH выполняются параллельно (в случайном порядке).Это невозможно. Последующие по тексту CTE могут использовать результаты предыдущих. При этом могут содержать группировки и оконные функции, выполнение которых невозможно без наличия окончательного набора записей источника данных. Т.е. при параллельном, тем более случайном, порядке, результат станет непредсказуемым. https://postgrespro.ru/docs/postgresql/11/queries-with#QUERIES-WITH-MODIFYING Важно понимать, что временная таблица, которую можно будет использовать в остальном запросе, создаётся из результата RETURNING, а не целевой таблицы оператора. Обрати внимание, что CTE1, поставляющий источник данных для финального запроса - это SELECT. У которого в принципе нет никакого RETURNING. Так что процитированная фраза как минимум рассматривает только частный случай, и в данной конкретной схеме - просто неприменима. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2019, 09:39 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
Akina, Согласен, цитата не та. Почему-то хотелось увидеть такой запрос: Код: sql 1. 2. 3.
... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2019, 13:19 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
Павел ЛузановПочему-то хотелось увидеть такой запрос: Если в такой форме запроса использовать RETURNING * , конечный результат будет тот же самый... с той лишь разницей, что в ходе выполнения у нас будет "лишний" этап фактически копирования исходных данных в RETURNING-набор, который не требуется в моём исходном запросе. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2019, 14:54 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
AkinaVSVLADИтого, как я понял, запросы в WITH выполняются параллельно (в случайном порядке).Это невозможно. Последующие по тексту CTE могут использовать результаты предыдущих. "выполняться" не атомарное понятие. все записи , которые д.б. изменены в кте должны быть залочены на момент "снепшота кте". т.е. делете не должен ещё стартовать , якобы, но залочить строки на изменение уже должен. т.е. должен "начать "выполняться " в части наложения блокировок. второй вариант -- лочить отложенно -- но столько раз рестартовать кте полностью, сколько раз нарушится "унутренний рипитбл-рид" к моменту делета -- чтобы выдержать единство снепшота для всех коленец кте грубо говоря там скорее всего ([не]?явные) ошибки сериализации возможны для случая сложного исчисления изменяемых в дальнейшем строк в предселектах. или долгий "вейт с повторами пред--исчисления" (рестарт снепшота кте -- т.к. изменяемые строки должны удовлетворять репитеблу внутре кте. т.е. надо смотреть реализацию, чтобы понять, как лучше. ) ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2019, 16:06 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
qwwqвсе записи , которые д.б. изменены в кте должны быть залочены на момент "снепшота кте". т.е. делете не должен ещё стартовать , якобы, но залочить строки на изменение уже должен. т.е. должен "начать "выполняться " в части наложения блокировок. Вы не упустили тот момент, что процитированная Вами фраза говорит об общем случае, а не о конкретном рассматриваемом в начальном посте запросе? При параллельном выполнении CTE просто обязана возникнуть ситуация, когда запись одного CTE, которая должна быть залочена при выполнении другого CTE, ещё не получена, т.е. попросту не существует. Вы представляете себе процесс блокирования несуществующей записи? Я - нет. Это надо быть гадалкой, а не сервером БД. qwwqстолько раз рестартовать кте полностью, сколько раз нарушится "унутренний рипитбл-рид" к моменту делета -- чтобы выдержать единство снепшота для всех коленец кте Т.е. получить такой оверхед, который с гарантией сожрёт и профит от параллельного исполнения, и ещё прихватит? А ведь для оконных функций появление ещё одной записи в группе запросто может потребовать не только блокировки "свежей" записи, но и блокировки/разблокировки ранее существовавших записей - т.е. фактически похерь всё сделанное ранее и начинай всю работу с самого начала. ... |
|||
:
Нравится:
Не нравится:
|
|||
06.06.2019, 07:31 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
Akina, йа ничего не цытирую, я пытаюсь додумать, как оно реализует внутренний строгий общий для всех коленец снепшот, если блокирующие коленца лежат строго позже долгих неблокирующих вычислений скорее всего примерно так же , как и более высокие уровни изоляции -- к моменту обработки записи в очередном коленце проверяется отсутствие конкурирующих изменений в блокируемых но не измененных нами же записях с момента снапшота , тако же как отсутствие лока( -- который требует отложить общий снепшот). а оверхед в транзакционной субд -- он проза жызни . о чом и пробую предупредить. не ходите дети в африку гулять. т.е. сразу взять делет -- оно дешевле может выйти. и причом тут оконные хункции , если в пж есть даже модифицирующие. ... |
|||
:
Нравится:
Не нравится:
|
|||
06.06.2019, 07:51 |
|
Нетривиальное использование CTE - нет ли подводных камней?
|
|||
---|---|---|---|
#18+
Akinaкогда запись одного CTE, которая должна быть залочена при выполнении другого CTE, ещё не получена, т.е. попросту не существует. Вы представляете себе процесс блокирования несуществующей записи? А ведь для оконных функций появление ещё одной записи в группе запросто может потребовать не только блокировки "свежей" записи, но и блокировки/разблокировки ранее существовавших записей - т.е. фактически похерь всё сделанное ранее и начинай всю работу с самого начала. не истерите запись невидимая до снепшота "не существует" для всех коленец кте и для любых хотя бы и дверных функций а не токмо оконных. пж это определяет по служебным полям. ... |
|||
:
Нравится:
Не нравится:
|
|||
06.06.2019, 07:58 |
|
|
start [/forum/topic.php?fid=53&tid=1995171]: |
0ms |
get settings: |
11ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
52ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
51ms |
get tp. blocked users: |
2ms |
others: | 16ms |
total: | 170ms |
0 / 0 |