Pull to refresh
8K+
2
Виктор Долгих@viktdo

User

5
Rating
Send message

Согласен по принципу: руками в psql прогнать запрос - первый шаг отладки, и сразу бы дал ошибку. Подвох в моём случае был в том, что я не подозревал что проблема в SQL. Нода в n8n возвращала пустой массив без сигнала об ошибке (из-за настройки «Continue using error output»), для меня в момент диагностики этот SQL-запрос был «уже выполнившимся успешно» - просто пустой результат, что в read-only-эндпоинте нормально (лида может не быть).

В реальной разработке час-два уходит именно на сужение где искать: фронт? сериализация? n8n? Только когда дошёл до SQL, открыл psql и увидел ошибку первой же строкой. После этого случая правило «дёргай запрос руками при любых странностях» поднял в pre-deploy чек-лист. Просто триггер у меня сработал поздно.

Могу использовать ваш комент, если соберусь написать статью по этой теме. Если будет применимо? С указанием на вас, конечно же

Могу использовать ваш комент, если соберусь написать статью по этой теме. Если будет применимо? С указанием на вас, конечно же

Могу использовать ваш комент, если соберусь написать статью по этой теме. Если будет применимо? С указанием на вас, конечно же

Соглашусь, тут вы попали в точку. Я не профильный SQL-специалист, мой основной стек это n8n / интеграции / API-обвязка, а Postgres использую в роли хранилища данных для воркфлоу, иногда для обработки данных на стороне Posgres. То есть пишу SELECT’ы и JOIN’ы регулярно, а в углы спецификации UNION захожу раз в полгода. Эта недетерминированность для меня действительно не была очевидной из чтения запроса, я думал про неё на уровне «обычно работает» и не пошёл дальше.

Ваш разбор как раз ценен тем, что показывает другой уровень владения инструментом: у человека с настоящим SQL-бэкграундом MAX-aggregate-обёртка уже в моторике, а не выводится из соображений. У меня так с n8n или JavaScript внутри Code-нод, где косяки чужих воркфлоу видны с первого взгляда. С Postgres мне до этого далеко, и комменты вроде ваших как раз тот ускоренный апдейт моторики, ради которого и пишутся такие статьи.

Спасибо за бенчмарк, MAX-aggregate подход я не пробовал и он действительно элегантнее моего RIGHT JOIN-варианта. План у него получается короче на одну ноду (Aggregate + Limit + Index Scan против Nested Loop Left Join + Result + Limit + Index Scan), и это гарантированно одна строка по семантике агрегата, без танцев с константной правой таблицей.

Один момент про safety этого паттерна: трюк работает только потому, что внутренний LIMIT 1 гарантирует не более одной строки на входе у MAX(). Если кто-то скопирует приём и уберёт LIMIT (или не заметит что подзапрос может вернуть >1 строки), то MAX(summary) и MAX(created_at) перестанут соответствовать друг другу. Это будут максимумы независимых колонок, и фронт получит «франкенштейн-строку» из несвязанных полей разных лидов. Я бы в продакшене вокруг такого запроса оставил коммент прямо в SQL: -- Aggregate trick: requires inner LIMIT 1, otherwise MAX() per-column desyncs rows.

С этой оговоркой соглашусь, что вариант чище RIGHT JOIN'а. Обновлённая иерархия для случая «вернуть ровно одну строку или fallback с NULL»: Aggregate-обёртка > UNION ALL с NULLS LAST > RIGHT JOIN с константной таблицей. На практике разница в 0.01 ms незначима, но план короче, значит читать и поддерживать проще, и Postgres в более сложных запросах будет оптимизировать предсказуемее.

Если коротко: посыл не про сам SQL, а про то, сколько слоёв проглатывают syntax error прежде чем он доходит до разработчика. Сам фикс действительно тривиальный, в статье я и пишу, что баг искал не в нём, а в системе вокруг.

Цепочка получилась такая: PostgreSQL-нода n8n с настройкой «Continue (using error output)» молча отдала пустой массив вместо исключения, downstream-нода с пустым массивом не упала а пробросила пустой объект, Respond to Webhook вернул HTTP 200 и пустое тело, фронт показал «нет данных», логи n8n executions показали статус success. Пять уровней, и ни на одном ошибка не материализовалась. Про SQL-pitfall я в итоге узнал последним, когда руками скопировал запрос в psql.

Полезный для меня вывод оттуда не «не забывай про скобки», а «не используй Continue using error output без подключённого error-выхода». В проектах где много динамического SQL эта настройка превращает любую опечатку в тихий 200 OK.

Кому скобки очевидны сразу, статья в первую очередь не для них. Для тех у кого в стеке n8n / Zapier / Make или любой low-code в продакшене, история про silent failures поверх SQL-ошибки полезнее самого SQL.

Поправка по делу, спасибо. Действительно, UNION ALL без внешнего ORDER BY порядок не гарантирует, и LIMIT 1 в моём варианте 1 теоретически может срезать найденную запись. Это баг, в продакшене стрельнул бы рано или поздно.

Правильный вариант, как вы и привели: ORDER BY created_at NULLS LAST LIMIT 1 поверх объединённого набора. Тогда найденная запись всегда выигрывает у NULL-fallback'а.

У меня в работающем флоу в итоге стоит RIGHT JOIN (вариант 2 в статье), там проблема снимается конструктивно: если внутренний SELECT пустой, RIGHT JOIN сам даёт NULL'ы, если вернул строку, она и есть результат. Но для «правильного UNION ALL» ваш вариант каноничный.

Про обрамление скобками каждого подзапроса даже без ORDER BY/LIMIT согласен. Парсер прощает, но через полгода ты сам не помнишь, какое правило приоритета у UNION с LIMIT, и скобки сильно облегчают чтение. Особенно когда запрос дорастает до WITH или вложенных UNION.

Да - это тоже есть в планах. Спасибо

Спасибо - на следующей неделе как раз буду готовить новый пак статей (50-100 шт) попробую внедрить ваш вариант

из web-интерфейса можно получить больше информации, как и указал в статье, но если задача массовая и не профильная, как у меня, очень помогает автоматизировать и повысить качество заголовков. Например веду канал в Дзен для перелива трафика на бота - контент на 90% нейрослоп и после внедрения автоматической подгонки заголовков открываемость поднялась в несколько раз. Руками на эту же работу я бы потратил времени больше чем на редактирование генеративного контента и залив его на площадку...

Хороший обзор для входа. От себя добавлю практический нюанс к тезису "кастомные GPT закрывают до 80% запросов поддержки" — цифра реалистичная, но только если есть чистая база знаний и нормальный fallback на человека. На проектах, где GPT подключали "поверх хаоса" из устаревших FAQ и PDF-ок, автоответы уходили в 30–40%, а остальное превращалось в галлюцинации. Самоокупается история обычно на 2-м месяце после того, как причешут контент — именно эта часть работы обычно и недооценивается на старте.

Спасибо, пункт про DOCKER_API_VERSION=1.41 сэкономил бы нам пару часов — ловили ровно этот же симптом на Traefik 3.3 и сначала грешили на лейблы. Ещё добавлю из своего опыта миграций n8n: перед pg_restore стоит временно выключить воркеры (N8N_DISABLE_PRODUCTION_MAIN_PROCESS + остановить queue-режим), иначе на больших инстансах ловили гонку — executions начинали писаться в ещё не до конца восстановленную схему. И да, N8N_ENCRYPTION_KEY — это то, на чём обжигаются буквально все, кто мигрирует впервые; хорошо, что вы вынесли это отдельным акцентом.

Про "меньше валидации и больше возражений" — подтверждаю, в code review прямо чувствуется: 4.6 чаще соглашался и уходил реализовывать сомнительное решение, 4.7 останавливает и просит уточнить. Для агентных пайплайнов это плюс, но в клиентских чат-ботах пришлось переписывать часть system-промптов — модель стала чаще пушбекать на формулировках пользователя, где раньше мягко переформулировала. Ещё наблюдение: дефолт xhigh в Code заметно меняет экономику длинных сессий, имеет смысл явно опускать до medium на рутинных правках, иначе бюджет уходит быстрее, чем в 4.6.

Замеры в точку, у нас похожая картина на продакшен-нагрузке: на русскоязычных промптах (саппорт-боты, длинные системные инструкции) рост около 1.4x, на коде ближе к 1.3x. Для тех, кто упирается в бюджет — помогает чуть агрессивнее включать prompt caching на system-части и few-shot примерах; на повторяющихся цепочках компенсирует почти весь прирост токенов. А вот +5 п.п. на IFEval при таком росте стоимости — действительно тяжело оправдать, если задача не требует строгого следования формату. Было бы интересно увидеть замеры ещё и по latency на одинаковых задачах.

Information

Rating
1,094-th
Location
Томск, Томская обл., Россия
Date of birth
Registered
Activity

Specialization

Фулстек разработчик, Веб-разработчик
Ведущий
Управление проектами
Разработка ТЗ
Автоматизация процессов
Оптимизация бизнес-процессов