В Postgres 18 появилась новая фича для ограничений по временным диапазонам:
- создаёт индекс, который комбинирует range и int
- не даёт добавлять дублирующиеся временные записи
👉 @SQLPortal
WITHOUT OVERLAPS. Это прям то, что нужно для систем бронирований, и в целом заметно проще, чем прошлые решения.CREATE EXTENSION IF NOT EXISTS btree_gist;
CREATE TABLE staff_schedule (
staff_id int,
shift_duration tstzrange,
task_description text,
PRIMARY KEY (staff_id, shift_duration WITHOUT OVERLAPS)
);
- создаёт индекс, который комбинирует range и int
- не даёт добавлять дублирующиеся временные записи
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8
Неиспользуемые индексы в PostgreSQL: риски, обнаружение и безопасное удаление
Индексы нужны, чтобы ускорять доступ к данным. Они позволяют PostgreSQL избегать full scan по таблице и заметно сокращают время выполнения запросов в read-heavy нагрузках.
По реальному прод-опыту мы видели, что грамотно спроектированные, точечные индексы могут ускорять запросы в 5 раз и больше, особенно на больших транзакционных таблицах.
Но индексы не бесплатны.
В этом посте разберем, какие проблемы могут создавать неиспользуемые индексы и как удалять их в проде безопасно, с планом отката.
1. Почему большие неиспользуемые индексы со временем становятся проблемой
Со временем такие индексы могут незаметно ухудшать производительность базы. Вот типовые эффекты, которые встречаются в проде.
1.1. Медленнее INSERT, UPDATE и DELETE
Каждая запись должна обновить все индексы таблицы, включая те, которыми запросы никогда не пользуются.
1.2. Больше нагрузки на VACUUM и autovacuum
В индексах так же копятся мертвые tuple, как и в таблицах. Их тоже нужно вакуумить, из-за чего растут I/O и время работы vacuum.
1.3. Дольше окна обслуживания
Операции вроде VACUUM и REINDEX выполняются тем дольше, чем больше индексов и чем они крупнее.
1.4. Пустая трата диска и “засорение” кеша
Большие неиспользуемые индексы едят место на диске и могут вытеснять полезные данные из shared_buffers, снижая эффективность кеша.
Поэтому периодически находить и аккуратно удалять неиспользуемые индексы в проде реально полезно, но только через контролируемый и хорошо проверенный процесс.
2. Как безопасно удалить неиспользуемые индексы в PostgreSQL
Ниже чеклист в стиле “можно в прод”, который стоит пройти перед удалением любого индекса.
2.1. Проверь, когда в последний раз сбрасывали статистику
Если статистику недавно reset’нули, индекс может выглядеть “неиспользуемым”, хотя он нужен под нагрузкой.
Старый
2.2. Проверь, не обслуживает ли индекс constraint
Большой индекс может быть “нулевым” по статистике, но удалять его нельзя, если он обеспечивает PRIMARY KEY, UNIQUE или FOREIGN KEY constraint.
PostgreSQL использует такие индексы для гарантий целостности и не даст их удалить, пока не удалишь сам constraint.
Если запрос вернул строки, этот индекс удалять нельзя.
2.3. Проверь статистику использования индекса
Так ты подтверждаешь, что планировщик реально не использовал индекс при выполнении запросов.
Все счетчики должны быть
3. Подготовь откат
Перед удалением всегда сохрани DDL индекса, чтобы быстро пересоздать при необходимости.
Сохрани результат как часть rollback-плана.
4. Удаляй безопасно
Если после удаления увидишь деградацию, откатный DDL можно использовать, чтобы пересоздать индекс concurrently без потери доступности.
5. Итог
Удаление неиспользуемых индексов может ощутимо улучшить производительность и упростить обслуживание, но только если действовать аккуратно.
Не полагайся на статистику в одиночку: проверяй constraints, понимай паттерны нагрузки и всегда готовь rollback.
В проде корректность и стабильность важнее скорости “уборки”.
👉 @SQLPortal
Индексы нужны, чтобы ускорять доступ к данным. Они позволяют PostgreSQL избегать full scan по таблице и заметно сокращают время выполнения запросов в read-heavy нагрузках.
По реальному прод-опыту мы видели, что грамотно спроектированные, точечные индексы могут ускорять запросы в 5 раз и больше, особенно на больших транзакционных таблицах.
Но индексы не бесплатны.
В этом посте разберем, какие проблемы могут создавать неиспользуемые индексы и как удалять их в проде безопасно, с планом отката.
1. Почему большие неиспользуемые индексы со временем становятся проблемой
Со временем такие индексы могут незаметно ухудшать производительность базы. Вот типовые эффекты, которые встречаются в проде.
1.1. Медленнее INSERT, UPDATE и DELETE
Каждая запись должна обновить все индексы таблицы, включая те, которыми запросы никогда не пользуются.
1.2. Больше нагрузки на VACUUM и autovacuum
В индексах так же копятся мертвые tuple, как и в таблицах. Их тоже нужно вакуумить, из-за чего растут I/O и время работы vacuum.
1.3. Дольше окна обслуживания
Операции вроде VACUUM и REINDEX выполняются тем дольше, чем больше индексов и чем они крупнее.
1.4. Пустая трата диска и “засорение” кеша
Большие неиспользуемые индексы едят место на диске и могут вытеснять полезные данные из shared_buffers, снижая эффективность кеша.
Поэтому периодически находить и аккуратно удалять неиспользуемые индексы в проде реально полезно, но только через контролируемый и хорошо проверенный процесс.
2. Как безопасно удалить неиспользуемые индексы в PostgreSQL
Ниже чеклист в стиле “можно в прод”, который стоит пройти перед удалением любого индекса.
2.1. Проверь, когда в последний раз сбрасывали статистику
Если статистику недавно reset’нули, индекс может выглядеть “неиспользуемым”, хотя он нужен под нагрузкой.
SELECT
datname,
stats_reset
FROM pg_stat_database
WHERE datname = current_database();
Старый
stats_reset (или NULL, то есть статистику никогда не сбрасывали) дает больше доверия метрикам использования индексов.2.2. Проверь, не обслуживает ли индекс constraint
Большой индекс может быть “нулевым” по статистике, но удалять его нельзя, если он обеспечивает PRIMARY KEY, UNIQUE или FOREIGN KEY constraint.
PostgreSQL использует такие индексы для гарантий целостности и не даст их удалить, пока не удалишь сам constraint.
SELECT
i.relname AS index_name,
c.conname AS constraint_name,
c.contype AS constraint_type,
c.conrelid::regclass AS table_name
FROM pg_constraint c
JOIN pg_class i ON i.oid = c.conindid
WHERE i.relname = '<IDX_NAME>';
Если запрос вернул строки, этот индекс удалять нельзя.
2.3. Проверь статистику использования индекса
Так ты подтверждаешь, что планировщик реально не использовал индекс при выполнении запросов.
SELECT
s.indexrelname AS index_name,
s.relname AS table_name,
s.idx_scan,
s.idx_tup_read,
s.idx_tup_fetch
FROM pg_stat_user_indexes s
WHERE s.indexrelname = '<IDX_NAME>';
Все счетчики должны быть
0.3. Подготовь откат
Перед удалением всегда сохрани DDL индекса, чтобы быстро пересоздать при необходимости.
SELECT pg_get_indexdef('<IDX_NAME>'::regclass) AS create_index_sql;Сохрани результат как часть rollback-плана.
4. Удаляй безопасно
DROP INDEX CONCURRENTLY не блокирует чтение и запись по таблице, поэтому подходит для прода.DROP INDEX CONCURRENTLY <IDX_NAME>;
Если после удаления увидишь деградацию, откатный DDL можно использовать, чтобы пересоздать индекс concurrently без потери доступности.
5. Итог
Удаление неиспользуемых индексов может ощутимо улучшить производительность и упростить обслуживание, но только если действовать аккуратно.
Не полагайся на статистику в одиночку: проверяй constraints, понимай паттерны нагрузки и всегда готовь rollback.
В проде корректность и стабильность важнее скорости “уборки”.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤3👍3
This media is not supported in your browser
VIEW IN TELEGRAM
То, что Postgres в одиночку не тянет, он может закрывать вместе с DuckDB.
Расширение pg_duckdb показывает, как две базы могут работать в связке: аналитические данные крутятся в DuckDB, а потом джойнятся с транзакционными данными в Postgres. Фишка в том, что расширение встраивает DuckDB прямо внутрь Postgres. DuckDB буквально запускается внутри процесса Postgres.
Как это работает (см. диаграмму):
1. Приложение отправляет запрос в Postgres, который джойнит данные портфеля (Postgres) с историческими рыночными данными (lakehouse)
2. pg_duckdb видит доступ к lakehouse и делегирует выполнение DuckDB
3. DuckDB подтягивает нужные рыночные данные из lakehouse, читает таблицы Postgres и делает join
4. Postgres возвращает приложению финальный результат
👉 @SQLPortal
Расширение pg_duckdb показывает, как две базы могут работать в связке: аналитические данные крутятся в DuckDB, а потом джойнятся с транзакционными данными в Postgres. Фишка в том, что расширение встраивает DuckDB прямо внутрь Postgres. DuckDB буквально запускается внутри процесса Postgres.
Как это работает (см. диаграмму):
1. Приложение отправляет запрос в Postgres, который джойнит данные портфеля (Postgres) с историческими рыночными данными (lakehouse)
2. pg_duckdb видит доступ к lakehouse и делегирует выполнение DuckDB
3. DuckDB подтягивает нужные рыночные данные из lakehouse, читает таблицы Postgres и делает join
4. Postgres возвращает приложению финальный результат
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Postgres бывает реально коварным, когда в тексте намешан разный регистр. Для поиска и индексации такого текста есть расширение citext, оно в некоторых случаях помогает. И это поле/тип тоже можно индексировать обычным b-tree.
- запросы могут находить результаты в любом регистре и в любой комбинации
- обычные text и varchar нельзя проиндексировать как регистронезависимые, а citext можно
- также помогает с UNIQUE-ограничениями на текст, когда на вход прилетает разный регистр
👉 @SQLPortal
- запросы могут находить результаты в любом регистре и в любой комбинации
- обычные text и varchar нельзя проиндексировать как регистронезависимые, а citext можно
- также помогает с UNIQUE-ограничениями на текст, когда на вход прилетает разный регистр
-- Подключаем расширение
CREATE EXTENSION IF NOT EXISTS citext;
-- Создаем таблицу с типом citext
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name CITEXT UNIQUE NOT NULL,
description TEXT
);
``` :contentReference[oaicite:0]{index=0}
::contentReference[oaicite:1]{index=1}
Please open Telegram to view this post
VIEW IN TELEGRAM
😁2
Правило SQL про GROUP BY, которое должен знать каждый
Если ты выбираешь в SELECT неагрегированные колонки, добавь их в GROUP BY. Это не просто хорошая практика, в некоторых СУБД без этого будет ошибка.
Почему это важно? Потому что GROUP BY определяет, что именно значит одна строка результата. Базе нужно понимать, какое единственное значение положить в каждую ячейку этой строки.
В примере выше одна строка = должность (job_title) внутри отдела (department).
Поэтому и department, и job_title обязаны быть в GROUP BY.
Если неагрегированную колонку не добавить:
❌ часть баз сразу упадет с ошибкой
❌ другие молча вернут случайные значения
❌ запрос может "работать" сегодня и врать завтра
Общее правило: Каждая колонка в SELECT должна быть функционально зависима от GROUP BY. Если внутри группы у колонки может быть несколько значений, она не может появляться в SELECT, пока:
- ты не добавил ее в GROUP BY, или
- не завернул в агрегатную функцию.
👉 @SQLPortal
Если ты выбираешь в SELECT неагрегированные колонки, добавь их в GROUP BY. Это не просто хорошая практика, в некоторых СУБД без этого будет ошибка.
Почему это важно? Потому что GROUP BY определяет, что именно значит одна строка результата. Базе нужно понимать, какое единственное значение положить в каждую ячейку этой строки.
В примере выше одна строка = должность (job_title) внутри отдела (department).
Поэтому и department, и job_title обязаны быть в GROUP BY.
Если неагрегированную колонку не добавить:
Общее правило: Каждая колонка в SELECT должна быть функционально зависима от GROUP BY. Если внутри группы у колонки может быть несколько значений, она не может появляться в SELECT, пока:
- ты не добавил ее в GROUP BY, или
- не завернул в агрегатную функцию.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
Совет по Postgres для SSD: поставь
👉 @SQLPortal
random_page_cost ниже. Значение по умолчанию 4.0 больше подходит для HDD (вращающихся дисков). На SSD можно опустить до 1.1 или 1.5, потому что случайные и последовательные чтения почти одинаковы по стоимости. Это помогает оптимизатору выбирать более удачные планы выполнения.Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Postgres продолжает развиваться в сторону gen AI. Тут наткнулся на два новых расширения.
VectorChord (vchord) это расширение для более дешевого и дисково-эффективного поиска похожих векторов. Обещают, что можно хранить 400 000 векторов всего за $1, и за счет этого получается ощутимая экономия: в 6 раз больше векторов по сравнению с оптимизированным хранилищем Pinecone и в 26 раз больше, чем у pgvector.
pgpu это еще одно расширение, которое умеет использовать NVIDIA GPU через CUDA, чтобы ускорять отдельные операции в базе и/или переносить их с CPU на GPU. Сейчас основной кейс это ускорение времени сборки индексного типа vchord с помощью GPU.
На диаграмме показано, как pgpu считает центроиды для индекса vchord с использованием GPU:
1. читаем данные из базы
2. считаем центроиды на GPU
3. пишем центроиды в таблицу Postgres
4. создаем индекс vchord, передавая таблицу с заранее посчитанными центроидами
👉 @SQLPortal
VectorChord (vchord) это расширение для более дешевого и дисково-эффективного поиска похожих векторов. Обещают, что можно хранить 400 000 векторов всего за $1, и за счет этого получается ощутимая экономия: в 6 раз больше векторов по сравнению с оптимизированным хранилищем Pinecone и в 26 раз больше, чем у pgvector.
pgpu это еще одно расширение, которое умеет использовать NVIDIA GPU через CUDA, чтобы ускорять отдельные операции в базе и/или переносить их с CPU на GPU. Сейчас основной кейс это ускорение времени сборки индексного типа vchord с помощью GPU.
На диаграмме показано, как pgpu считает центроиды для индекса vchord с использованием GPU:
1. читаем данные из базы
2. считаем центроиды на GPU
3. пишем центроиды в таблицу Postgres
4. создаем индекс vchord, передавая таблицу с заранее посчитанными центроидами
Please open Telegram to view this post
VIEW IN TELEGRAM
БОЛЬШОЙ SQL грех
Никогда не пихай ORDER BY внутрь CTE (или подзапроса), если там же рядом нет LIMIT.
Если LIMIT забыть, база обычно будет сортировать всю таблицу вообще без смысла.
👉 @SQLPortal
Никогда не пихай ORDER BY внутрь CTE (или подзапроса), если там же рядом нет LIMIT.
Если LIMIT забыть, база обычно будет сортировать всю таблицу вообще без смысла.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Быстрый sanity check: не забыли ли вы критичные индексы?
Если видишь много seq scan и при этом почти нет idx_scan, значит таблицы часто читаются последовательным сканом и, скорее всего, где-то реально просится индекс.
👉 @SQLPortal
SELECT relname, seq_scan, seq_tup_read, idx_scan
FROM pg_stat_user_tables
WHERE seq_scan > 0
ORDER BY seq_tup_read DESC
LIMIT 10;
Если видишь много seq scan и при этом почти нет idx_scan, значит таблицы часто читаются последовательным сканом и, скорее всего, где-то реально просится индекс.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2
Не пиши в SQL = NULL или != NULL
Для NULL всегда используй IS NULL / IS NOT NULL
NULL это “нет значения / неизвестно”, и обычные операторы сравнения (=, !=, <, >) с ним не работают, потому что NULL не равен, не больше и не меньше вообще ничего.
= / != сравнивают значения. А NULL это не значение, а отсутствие значения. Поэтому IS / IS NOT проверяют именно наличие или отсутствие значения.
👉 @SQLPortal
Для NULL всегда используй IS NULL / IS NOT NULL
NULL это “нет значения / неизвестно”, и обычные операторы сравнения (=, !=, <, >) с ним не работают, потому что NULL не равен, не больше и не меньше вообще ничего.
= / != сравнивают значения. А NULL это не значение, а отсутствие значения. Поэтому IS / IS NOT проверяют именно наличие или отсутствие значения.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27❤4
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