warda bibi: Раскрываем высокую производительность PostgreSQL: ключевые оптимизации памяти
👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Stormatics
Unlocking High-Performance PostgreSQL: Key Memory Optimizations
A practical, production-focused guide to PostgreSQL memory tuning, with a deep dive into shared_buffers and work_mem, how they work, how they scale under concurrency, and how to tune them safely using real metrics.
👍2
БОЛЬШОЙ SQL-грех
Использовать
В SQL оператор
Если нужно учитывать
Всегда тестируйте запросы на данных с
👉 @SQLPortal
Использовать
NOT IN или IN, когда в данных (или в списке) могут быть NULL.В SQL оператор
IN это сокращение для набора условий через OR, а сравнение value = NULL всегда даёт UNKNOWN. Из-за этого запрос чаще всего вернёт пустой результат.Если нужно учитывать
NULL, обрабатывайте их явно: добавляйте условие IS NULL вместе с IN, или используйте другой подход, который корректно учитывает NULL.Всегда тестируйте запросы на данных с
NULL, чтобы убедиться, что они реально ведут себя так, как вы ожидаете.Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍8
Postgres 18 теперь поддерживает OAUTH 2.0 для аутентификации пользователей.
Также в Postgres 18 log_line_prefix теперь может включать %L для вывода IP-адреса клиента.
👉 @SQLPortal
Также в Postgres 18 log_line_prefix теперь может включать %L для вывода IP-адреса клиента.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1🤔1
Строки в PostgreSQL неизменяемые и хранятся в heap. У каждой строки есть скрытый идентификатор CTID, который указывает на ее физическое местоположение на диске.
CTID это идентификатор-кортеж из двух частей: номер страницы и индекс (позиция) внутри этой страницы. Посмотреть его можно простым запросом:
Вывод будет выглядеть примерно так:
Что в CTID интересного: когда ты создаешь индекс по первичному ключу, индекс не хранит всю строку целиком. Он хранит значение ключа и CTID, который указывает на реальное место строки в heap.
Из-за этого выборки быстрые. Индекс дает CTID, и PostgreSQL прыгает напрямую в нужную физическую точку в heap, чтобы достать строку.
Но есть нюанс: CTID меняется при обновлении строки. PostgreSQL использует MVCC (Multi-Version Concurrency Control), поэтому update создает новую версию строки в другом физическом месте. Старый CTID становится невалидным, а у строки появляется новый.
Из-за этого индексы нужно обновлять при каждом обновлении строки. Значение ключа может остаться тем же, но CTID, на который оно указывает, меняется.
Интересные архитектурные решения. PostgreSQL сэкономил одно лишнее разыменование, сохраняя CTID, но теперь индекс нужно переписывать даже если меняются неиндексируемые колонки.
Вот почему я обожаю копаться во внутренностях СУБД :) Там сплошь интересные решения и компромиссы.
👉 @SQLPortal
CTID это идентификатор-кортеж из двух частей: номер страницы и индекс (позиция) внутри этой страницы. Посмотреть его можно простым запросом:
SELECT ctid, * FROM your_table;
Вывод будет выглядеть примерно так:
(0,1), (0,2), (1,1), где первое число это страница, а второе это позиция.Что в CTID интересного: когда ты создаешь индекс по первичному ключу, индекс не хранит всю строку целиком. Он хранит значение ключа и CTID, который указывает на реальное место строки в heap.
Из-за этого выборки быстрые. Индекс дает CTID, и PostgreSQL прыгает напрямую в нужную физическую точку в heap, чтобы достать строку.
Но есть нюанс: CTID меняется при обновлении строки. PostgreSQL использует MVCC (Multi-Version Concurrency Control), поэтому update создает новую версию строки в другом физическом месте. Старый CTID становится невалидным, а у строки появляется новый.
Из-за этого индексы нужно обновлять при каждом обновлении строки. Значение ключа может остаться тем же, но CTID, на который оно указывает, меняется.
Интересные архитектурные решения. PostgreSQL сэкономил одно лишнее разыменование, сохраняя CTID, но теперь индекс нужно переписывать даже если меняются неиндексируемые колонки.
Вот почему я обожаю копаться во внутренностях СУБД :) Там сплошь интересные решения и компромиссы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤1
Как получить топ-5 продавцов в SQL (с учётом ничьих)
❌ Первый вариант выглядит корректно, но он не учитывает ничьи. Если несколько продавцов делят 5-е место, SQL просто молча отбросит лишних.
✅ Если база данных поддерживает
✅ Для остальных СУБД выручит оконная функция — через
👉 @SQLPortal
FETCH FIRST … WITH TIES (например, PostgreSQL), второй вариант будет работать правильно и вернёт всех, кто делит место.RANK() или DENSE_RANK(). Она корректно обработает равные значения и ничего не потеряет.Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Гайд: материализованные представления в PostgreSQL — когда кэширование результатов запросов имеет смысл (и когда нет…)
👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
Stormatics
PostgreSQL Materialized Views: When Caching Your Query Results Makes Sense (And When It Doesn't) | Stormatics
Learn when PostgreSQL materialized views actually make sense, how to build and refresh them safely, and how they turn 30s queries into sub-second reads.
В Postgres есть несколько способов делать ранжирование с ORDER BY. С выбором нужно быть аккуратным, особенно если есть дубликаты значений.
RANK может пропускать номера, а DENSE_RANK выдает все ранги подряд, но при равных значениях присваивает одинаковый ранг.
👉 @SQLPortal
RANK может пропускать номера, а DENSE_RANK выдает все ранги подряд, но при равных значениях присваивает одинаковый ранг.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
This media is not supported in your browser
VIEW IN TELEGRAM
Позволь Postgres владеть Iceberg-каталогом, а аналитику делегировать DuckDB. В итоге получаешь транзакционные обновления lakehouse плюс быстрые аналитические запросы.
Это не концепт. Именно так pg_lake работает уже сегодня.
pg_lake объединяет набор расширений и компонентов, которые позволяют напрямую из Postgres читать и изменять Iceberg-таблицы (и другие lakehouse-форматы). Для ускорения аналитических запросов используется DuckDB, запущенный в сайдкар-процессе pgduck_server, который общается с Postgres во время выполнения запроса.
Как это работает:
1. Приложение отправляет запрос в Postgres, чтобы посчитать нереализованный PnL (profit and loss) по тикеру Disney.
2. Postgres парсит запрос и определяет часть, где считается средняя цена на основе исторических данных из lakehouse.
3. Эта часть запроса проксируется в pgduck_server для ускоренного выполнения.
4. pgduck_server передает выполнение в DuckDB, который читает данные из lakehouse (переиспользуя кэш, если он есть).
5. DuckDB считает среднюю цену и возвращает результат в Postgres.
6. Postgres джойнит этот результат с локальными данными портфеля и считает нереализованный PnL.
7. Финальный результат возвращается приложению.
👉 @SQLPortal
Это не концепт. Именно так pg_lake работает уже сегодня.
pg_lake объединяет набор расширений и компонентов, которые позволяют напрямую из Postgres читать и изменять Iceberg-таблицы (и другие lakehouse-форматы). Для ускорения аналитических запросов используется DuckDB, запущенный в сайдкар-процессе pgduck_server, который общается с Postgres во время выполнения запроса.
Как это работает:
1. Приложение отправляет запрос в Postgres, чтобы посчитать нереализованный PnL (profit and loss) по тикеру Disney.
2. Postgres парсит запрос и определяет часть, где считается средняя цена на основе исторических данных из lakehouse.
3. Эта часть запроса проксируется в pgduck_server для ускоренного выполнения.
4. pgduck_server передает выполнение в DuckDB, который читает данные из lakehouse (переиспользуя кэш, если он есть).
5. DuckDB считает среднюю цену и возвращает результат в Postgres.
6. Postgres джойнит этот результат с локальными данными портфеля и считает нереализованный PnL.
7. Финальный результат возвращается приложению.
Please open Telegram to view this post
VIEW IN TELEGRAM
Снижение ошибок оценки количества строк в PostgreSQL: читать
Планировщик запросов PostgreSQL опирается на статистику таблиц, чтобы оценить, сколько строк (estimated rows) будет обработано на каждом этапе выполнения, и на основе этих оценок выбрать оптимальный план выполнения. Когда оценка сильно расходится с реальным количеством строк, планировщик может выбрать неудачный план, что приводит к серьёзному падению производительности запросов.
В этой статье разбираются четыре подхода, которые использовали для снижения ошибок оценки количества строк, в порядке от наименее инвазивных к наиболее инвазивным. Из-за ограничений по конфиденциальности я не могу показать реальный SQL или планы выполнения, поэтому акцент сделан на диагностике, ходе рассуждений и применённых техниках.
👉 @SQLPortal
Планировщик запросов PostgreSQL опирается на статистику таблиц, чтобы оценить, сколько строк (estimated rows) будет обработано на каждом этапе выполнения, и на основе этих оценок выбрать оптимальный план выполнения. Когда оценка сильно расходится с реальным количеством строк, планировщик может выбрать неудачный план, что приводит к серьёзному падению производительности запросов.
В этой статье разбираются четыре подхода, которые использовали для снижения ошибок оценки количества строк, в порядке от наименее инвазивных к наиболее инвазивным. Из-за ограничений по конфиденциальности я не могу показать реальный SQL или планы выполнения, поэтому акцент сделан на диагностике, ходе рассуждений и применённых техниках.
Please open Telegram to view this post
VIEW IN TELEGRAM
DEV Community
Reducing row count estimation errors in PostgreSQL
Introduction PostgreSQL's query planner relies on table statistics to estimate the number...
👍3🔥2
Рекурсивные CTE в Postgres позволяют проходить по вложенным структурам или иерархиям и находить связи шаг за шагом. Ты задаёшь рекурсию, добавляешь anchor-запрос для старта, и дальше CTE будет итерироваться по данным, пока не дойдёт до конца.
👉 @SQLPortal
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
У индексов есть встроенный порядок сортировки. По умолчанию B-tree индекс идет по возрастанию с NULLS LAST.
Postgres умеет сканировать индекс как вперед, так и назад, поэтому во многих случаях это не имеет значения.
Но если порядок NULLS FIRST или NULLS LAST не совпадает с тем, что требуется в запросе, Postgres уже не сможет использовать этот индекс.
👉 @SQLPortal
Postgres умеет сканировать индекс как вперед, так и назад, поэтому во многих случаях это не имеет значения.
Но если порядок NULLS FIRST или NULLS LAST не совпадает с тем, что требуется в запросе, Postgres уже не сможет использовать этот индекс.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥2
Elasticsearch отлично работает в разработке. В продакшене все совсем иначе.
За годы эксплуатации ES-кластеров команды снова и снова натыкаются на одни и те же проблемы. Они всплывают в инцидент-репортах и вопросах на Stack Overflow. В статье собраны 10 самых частых:
» Паузы сборщика мусора JVM, которые запускают каскадные отказы
» Взрыв маппингов из-за полуструктурированных данных
» Математика с шардами, которую нужно угадать заранее (и потом уже не поменять)
» Глубокая пагинация, упирающаяся в жесткий лимит в 10 000 результатов
» Split-brain сценарии при сетевых разделениях
» Сюрпризы eventual consistency («я только что сохранил, но не могу найти»)
» Ошибки в настройке безопасности, которые приводили к массовым утечкам
» Сотни метрик, где понять, какие реально важны, можно только с глубокой экспертизой
» Пайплайны синхронизации данных между Postgres и ES, которые ломаются тихо
» Инфраструктурные затраты, растущие с каждым новым узлом
У всех этих проблем один корень: Elasticsearch — это отдельная система.
Отдельная инфраструктура, отдельная экспертиза, отдельные режимы отказа, отдельные пайплайны.
Теперь, когда BM25 доступен в Postgres через pg_textsearch, поиск можно оставить в основной базе. Без JVM, без шардов, без джобов синхронизации. Одна база, один источник истины.
В блоге разбирается каждая из проблем со ссылками на реальные инциденты и объясняется, как Postgres их избегает
👉 @SQLPortal
За годы эксплуатации ES-кластеров команды снова и снова натыкаются на одни и те же проблемы. Они всплывают в инцидент-репортах и вопросах на Stack Overflow. В статье собраны 10 самых частых:
» Паузы сборщика мусора JVM, которые запускают каскадные отказы
» Взрыв маппингов из-за полуструктурированных данных
» Математика с шардами, которую нужно угадать заранее (и потом уже не поменять)
» Глубокая пагинация, упирающаяся в жесткий лимит в 10 000 результатов
» Split-brain сценарии при сетевых разделениях
» Сюрпризы eventual consistency («я только что сохранил, но не могу найти»)
» Ошибки в настройке безопасности, которые приводили к массовым утечкам
» Сотни метрик, где понять, какие реально важны, можно только с глубокой экспертизой
» Пайплайны синхронизации данных между Postgres и ES, которые ломаются тихо
» Инфраструктурные затраты, растущие с каждым новым узлом
У всех этих проблем один корень: Elasticsearch — это отдельная система.
Отдельная инфраструктура, отдельная экспертиза, отдельные режимы отказа, отдельные пайплайны.
Теперь, когда BM25 доступен в Postgres через pg_textsearch, поиск можно оставить в основной базе. Без JVM, без шардов, без джобов синхронизации. Одна база, один источник истины.
В блоге разбирается каждая из проблем со ссылками на реальные инциденты и объясняется, как Postgres их избегает
Please open Telegram to view this post
VIEW IN TELEGRAM
Tiger Data Blog
10 Elasticsearch Production Issues
Why Elasticsearch is complex in production: garbage collection, shard math, data sync pipelines, and monitoring overhead.
👍4
SQL-хак, о котором мало кто знает
Знал, что можно юзать FILTER как альтернативу CASE в агрегатах?
Самое приятное, что условия отделяются от самой агрегации, и это проще дебажить.
Если твой SQL-движок поддерживает FILTER (PostgreSQL, SQLite, DuckDB), попробуй.
CASE или FILTER? Что тебе больше нравится?😆
👉 @SQLPortal
Знал, что можно юзать FILTER как альтернативу CASE в агрегатах?
Самое приятное, что условия отделяются от самой агрегации, и это проще дебажить.
Если твой SQL-движок поддерживает FILTER (PostgreSQL, SQLite, DuckDB), попробуй.
CASE или FILTER? Что тебе больше нравится?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Table bloat это одна из самых больших слабых сторон Postgres.
Каждый UPDATE строки создает новую копию строки, а старая остается лежать на месте. DELETE помечает строку как удаленную, а освобождение места откладывается на потом.
В базах с большой нагрузкой по UPDATE и DELETE в таблицах накапливаются тонны мертвых строк (tombstones), разбросанных по файлу таблицы. В итоге размер таблицы на диске выглядит гораздо больше, чем реально нужно.
Это и есть table bloat.
Мертвые строки могут переиспользоваться новыми строками, если те по размеру влезают, но иногда, чтобы реально вернуть все доступное мертвое место, нужен VACUUM FULL или похожая пересборка таблицы через расширения.
И это не случайный косяк дизайна: хранение старых версий строк полезно для MVCC и производительности. Просто за это платишь усложнением управления хранилищем :/
👉 @SQLPortal
Каждый UPDATE строки создает новую копию строки, а старая остается лежать на месте. DELETE помечает строку как удаленную, а освобождение места откладывается на потом.
В базах с большой нагрузкой по UPDATE и DELETE в таблицах накапливаются тонны мертвых строк (tombstones), разбросанных по файлу таблицы. В итоге размер таблицы на диске выглядит гораздо больше, чем реально нужно.
Это и есть table bloat.
Мертвые строки могут переиспользоваться новыми строками, если те по размеру влезают, но иногда, чтобы реально вернуть все доступное мертвое место, нужен VACUUM FULL или похожая пересборка таблицы через расширения.
И это не случайный косяк дизайна: хранение старых версий строк полезно для MVCC и производительности. Просто за это платишь усложнением управления хранилищем :/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
eBPF-трейсинг спинлоков PostgreSQL
PostgreSQL использует процессную архитектуру: каждое подключение обслуживается отдельным процессом. Часть структур данных шарится между этими процессами, например shared buffer cache или write-ahead log (WAL). Чтобы координировать доступ к этим общим ресурсам, PostgreSQL использует несколько механизмов блокировок, в том числе спинлоки.
Спинлоки рассчитаны на очень короткую защиту общих структур: вместо того чтобы сразу усыплять процесс, который ждёт, он крутится в busy-wait и снова и снова проверяет, освободился ли лок. При контеншене PostgreSQL ещё применяет adaptive backoff, который может включать короткие sleep.
В статье объясняется, что такое спинлоки и как они реализованы в PostgreSQL. Также описывается, как их мониторить, и показывается, как использовать мой новый инструмент pg_spinlock_tracer, чтобы трейсить внутренности спинлоков через eBPF.
👉 @SQLPortal
PostgreSQL использует процессную архитектуру: каждое подключение обслуживается отдельным процессом. Часть структур данных шарится между этими процессами, например shared buffer cache или write-ahead log (WAL). Чтобы координировать доступ к этим общим ресурсам, PostgreSQL использует несколько механизмов блокировок, в том числе спинлоки.
Спинлоки рассчитаны на очень короткую защиту общих структур: вместо того чтобы сразу усыплять процесс, который ждёт, он крутится в busy-wait и снова и снова проверяет, освободился ли лок. При контеншене PostgreSQL ещё применяет adaptive backoff, который может включать короткие sleep.
В статье объясняется, что такое спинлоки и как они реализованы в PostgreSQL. Также описывается, как их мониторить, и показывается, как использовать мой новый инструмент pg_spinlock_tracer, чтобы трейсить внутренности спинлоков через eBPF.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Что вернет этот запрос?
SELECT department, job_title, COUNT(*) AS cnt FROM employees GROUP BY department;
SELECT department, job_title, COUNT(*) AS cnt FROM employees GROUP BY department;
Anonymous Quiz
21%
A) Одна строка на департамент с корректными подсчетами
49%
B) Ошибка во всех базах данных
14%
C) Случайные значения job_title для каждого департамента
15%
D) Зависит от базы данных
💊10❤3🤯2🔥1
50 практических вопросов по SQL для отработки навыков запросов, часто появляющихся на собеседованиях
> SQL‑скрипты для создания тестовых данных (таблицы, вставка строк)
> Вопросы типа: «Напишите запрос, чтобы вывести уникальные значения», «Найдите N‑ю максимальную зарплату» и т.д.
> Готовые решения и объяснения
читать
👉 @SQLPortal
> SQL‑скрипты для создания тестовых данных (таблицы, вставка строк)
> Вопросы типа: «Напишите запрос, чтобы вывести уникальные значения», «Найдите N‑ю максимальную зарплату» и т.д.
> Готовые решения и объяснения
читать
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Если у тебя получается 3 и больше вложенных циклов, остановись и переделай.
Глубокая вложенность делает код плохо читаемым и сложным в поддержке.
Цель всегда одна: чтобы код было легко понять и безопасно менять.
Если видишь, что вложенность разрастается, подумай, как упростить: разбей на функции, вынеси логику в отдельные методы, используй более подходящие структуры данных или готовую библиотеку вместо самописных конструкций.
👉 @SQLPortal
Глубокая вложенность делает код плохо читаемым и сложным в поддержке.
Цель всегда одна: чтобы код было легко понять и безопасно менять.
Если видишь, что вложенность разрастается, подумай, как упростить: разбей на функции, вынеси логику в отдельные методы, используй более подходящие структуры данных или готовую библиотеку вместо самописных конструкций.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Мониторинг планов запросов с pgwatch и pg_stat_plans: читать
В экосистеме PostgreSQL появилась новая extension pg_stat_plans. Она похожа на pg_stat_statements, но собирает агрегированную статистику не по SQL-выражениям, а по планам выполнения запросов.
Она предоставляет SQL-интерфейс для доступа к этим метрикам через представление (view) pg_stat_plans. В этом посте покажут, насколько просто интегрировать такие расширения с pgwatch для тех, кто хочет улучшить или кастомизировать набор метрик, которые собираются с мониторируемой базы.
👉 @SQLPortal
В экосистеме PostgreSQL появилась новая extension pg_stat_plans. Она похожа на pg_stat_statements, но собирает агрегированную статистику не по SQL-выражениям, а по планам выполнения запросов.
Она предоставляет SQL-интерфейс для доступа к этим метрикам через представление (view) pg_stat_plans. В этом посте покажут, насколько просто интегрировать такие расширения с pgwatch для тех, кто хочет улучшить или кастомизировать набор метрик, которые собираются с мониторируемой базы.
Please open Telegram to view this post
VIEW IN TELEGRAM
CYBERTEC PostgreSQL | Services & Support
Monitoring query plans with pgwatch and pg_stat_plans
How to monitor query plans using pgwatch and pg_stat_plans. See step by step walkthrough showing how easy it is to integrate such extensions.
Что выбрать?
Оба варианта означают не равно.
✅ <> это стандарт SQL
Оператор <> определен стандартом ANSI SQL.
Он работает везде, во всех СУБД.
⚠️ != это поддержка от вендоров
Большинство современных СУБД понимают !=, но технически это не “родной” стандартный оператор. Его добавили в основном ради удобства разработчиков (ну потому что во многих языках используется !=).
Признаюсь, я сам чаще пишу != из-за привычек после Python.😂
Чаще используй <>.
Почему?
- это стандарт SQL
- максимально переносимо между СУБД
А ты как пишешь? Что чаще используешь, <> или !=?
👉 @SQLPortal
Оба варианта означают не равно.
Оператор <> определен стандартом ANSI SQL.
Он работает везде, во всех СУБД.
Большинство современных СУБД понимают !=, но технически это не “родной” стандартный оператор. Его добавили в основном ради удобства разработчиков (ну потому что во многих языках используется !=).
Признаюсь, я сам чаще пишу != из-за привычек после Python.
Чаще используй <>.
Почему?
- это стандарт SQL
- максимально переносимо между СУБД
А ты как пишешь? Что чаще используешь, <> или !=?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2