Что происходит, когда вы вставляете строку (INSERT) в Postgres?
Postgres должен обеспечить надёжное сохранение данных, не теряя в скорости записи и сохраняя возможность восстановиться после сбоя. Ключевую роль здесь играет журнал предзаписи (Write-Ahead Log, WAL).
1. Получение запроса
Postgres принимает запрос и определяет, на какую страницу данных поместить новую запись.
Эта страница может уже быть в памяти (в буфере), может быть подгружена с диска, а может быть создана заново.
2. Запись в память
Новая строка записывается только в страницу, находящуюся в оперативке.
Эта страница помечается как *грязная*, то есть её нужно будет когда-то сбросить на диск, но не сразу.
3. Формирование записи в WAL
В буфер WAL в памяти добавляется новая запись, содержащая всю информацию, нужную для восстановления этой операции вставки.
4. Сброс WAL на диск
WAL синхронно сбрасывается на диск (через
После успешного сброса Postgres отправляет клиенту ответ success.
Когда клиент получает подтверждение, данные уже точно записаны в WAL (а значит, безопасны с точки зрения crash recovery), но сами данные таблицы могут пока оставаться только в памяти.
Их сброс на диск произойдёт позже — при контрольных точках (checkpoint), в фоновом процессе или при вытеснении страниц из памяти.
Если сервер упадёт до того, как грязные страницы будут записаны, при старте Postgres просто воспроизведёт WAL и восстановит все зафиксированные изменения.
Он обеспечивает быструю запись и устойчивость к сбоям.
👉 @SQLPortal
Postgres должен обеспечить надёжное сохранение данных, не теряя в скорости записи и сохраняя возможность восстановиться после сбоя. Ключевую роль здесь играет журнал предзаписи (Write-Ahead Log, WAL).
1. Получение запроса
Postgres принимает запрос и определяет, на какую страницу данных поместить новую запись.
Эта страница может уже быть в памяти (в буфере), может быть подгружена с диска, а может быть создана заново.
2. Запись в память
Новая строка записывается только в страницу, находящуюся в оперативке.
Эта страница помечается как *грязная*, то есть её нужно будет когда-то сбросить на диск, но не сразу.
3. Формирование записи в WAL
В буфер WAL в памяти добавляется новая запись, содержащая всю информацию, нужную для восстановления этой операции вставки.
4. Сброс WAL на диск
WAL синхронно сбрасывается на диск (через
fsync или аналог). Это гарантирует, что данные попали в надёжное хранилище. После успешного сброса Postgres отправляет клиенту ответ success.
Когда клиент получает подтверждение, данные уже точно записаны в WAL (а значит, безопасны с точки зрения crash recovery), но сами данные таблицы могут пока оставаться только в памяти.
Их сброс на диск произойдёт позже — при контрольных точках (checkpoint), в фоновом процессе или при вытеснении страниц из памяти.
Если сервер упадёт до того, как грязные страницы будут записаны, при старте Postgres просто воспроизведёт WAL и восстановит все зафиксированные изменения.
WAL это сердце механизма надёжности Postgres.
Он обеспечивает быструю запись и устойчивость к сбоям.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12👍3🤯2
This media is not supported in your browser
VIEW IN TELEGRAM
DISTINCT ON в Postgres - это особый синтаксис SQL, который позволяет выбрать одну строку с максимальным, минимальным, первой или последней записью в пределах каждой группы.
Эта конструкция требует обязательного использования ORDER BY. Если две строки полностью идентичны, Postgres просто возьмёт одну из них.
👉 @SQLPortal
Эта конструкция требует обязательного использования ORDER BY. Если две строки полностью идентичны, Postgres просто возьмёт одну из них.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5
Один из разработчиков вошёл в топ-50 major контрибьюторов PostgreSQL — самой популярной опенсорс-СУБД в мире.
📊 PostgreSQL используют 55% разработчиков (по Stack Overflow 2025), а её возможности активно применяются в AI-проектов, включая ChatGPT — за счёт встроенного векторного поиска.
⚙️ Команда инженеров из Yandex Cloud делает регулярные коммиты PostgreSQL — их доработки проходят строгий отбор сообщества и попадают в официальные релизы.
💾 Среди компаний, использующих Managed PostgreSQL — Циан, Банки.ру, Русполимет.
Кроме того, команда разработала open-source-решение SPQR для шардирования PostgreSQL и запустила новый сервис для горизонтального масштабирования.
👉 Вклад команды помогает PostgreSQL оставаться одной из самых надёжных и масштабируемых СУБД в мире.
👉 @SQLPortal
📊 PostgreSQL используют 55% разработчиков (по Stack Overflow 2025), а её возможности активно применяются в AI-проектов, включая ChatGPT — за счёт встроенного векторного поиска.
⚙️ Команда инженеров из Yandex Cloud делает регулярные коммиты PostgreSQL — их доработки проходят строгий отбор сообщества и попадают в официальные релизы.
💾 Среди компаний, использующих Managed PostgreSQL — Циан, Банки.ру, Русполимет.
Кроме того, команда разработала open-source-решение SPQR для шардирования PostgreSQL и запустила новый сервис для горизонтального масштабирования.
👉 Вклад команды помогает PostgreSQL оставаться одной из самых надёжных и масштабируемых СУБД в мире.
👉 @SQLPortal
👍8❤4😁2
Появился ИИ-ассистент, который сам пишет и оптимизирует SQL-запросы.
Он понимает обычный язык, достаточно спросить «какие пользователи были активны за месяц?» и всё готово.
Сейчас поддерживается PostgreSQL, а скоро подтянутся MySQL и MongoDB.
Безопасность на месте: шифруются строки подключения, пароли и сами запросы.
Плюс можно выбрать, на какой модели работает ИИ
https://github.com/wannabespace/conar
👉 @SQLPortal
Он понимает обычный язык, достаточно спросить «какие пользователи были активны за месяц?» и всё готово.
Сейчас поддерживается PostgreSQL, а скоро подтянутся MySQL и MongoDB.
Безопасность на месте: шифруются строки подключения, пароли и сами запросы.
Плюс можно выбрать, на какой модели работает ИИ
https://github.com/wannabespace/conar
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5😁5🔥3
Макросы в Oracle SQL позволяют определять шаблоны выражений в виде текста.
На этапе парсинга база данных подставляет эти шаблоны в основной запрос, заменяя параметры на переданные значения.
Существует два типа макросов:
Scalar (скалярные) — используются в SELECT, WHERE, ORDER BY и других выражениях.
Table (табличные) — используются в FROM, чтобы инкапсулировать вычисления и бизнес-логику.
Примеры:
Скалярный макрос возвращает текст SQL-выражения, которое можно вставить прямо в запрос.
Табличный макрос возвращает SQL-подзапрос, который разворачивается в FROM как обычная таблица.
Начиная с Oracle 21c они официально поддерживаются, а табличные макросы были также бэкпортированы в 19.7.
👉 @SQLPortal
На этапе парсинга база данных подставляет эти шаблоны в основной запрос, заменяя параметры на переданные значения.
Существует два типа макросов:
Scalar (скалярные) — используются в SELECT, WHERE, ORDER BY и других выражениях.
Table (табличные) — используются в FROM, чтобы инкапсулировать вычисления и бизнес-логику.
Примеры:
Скалярный макрос возвращает текст SQL-выражения, которое можно вставить прямо в запрос.
Табличный макрос возвращает SQL-подзапрос, который разворачивается в FROM как обычная таблица.
Начиная с Oracle 21c они официально поддерживаются, а табличные макросы были также бэкпортированы в 19.7.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Базовые вещи по базам данных, которые стоит изучить, если хочешь реально разобраться в масштабировании:
Сохрани это.
👉 @SQLPortal
Сохрани это.
B+ деревья
LSM деревья
Write-Ahead Logging (журналирование перед записью)
Двухфазный коммит
Трёхфазный коммит
Реплики только для чтения
Репликация по схеме лидер–фолловер
Шардинг / партиционирование (Partitioning)
Кэширование запросов
Вторичные индексы
Векторные индексы (Vector Indexes, например FAISS, HNSW)
Распределённые JOIN’ы
Материализованные представления
Event Sourcing (событийное хранение состояния)
Change Data Capture (отслеживание изменений данных)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3
В выводе Postgres EXPLAIN есть полезная информация о том, что происходит с запросом.
Основные вещи, на которые стоит обратить внимание в плане EXPLAIN:
👉 @SQLPortal
Основные вещи, на которые стоит обратить внимание в плане EXPLAIN:
Использовался ли индекс?
Были ли данные уже в shared buffer cache?
Сколько времени заняло планирование и выполнение запроса.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2
Плохо написанный SQL легко превращается в тормозящий и трудноподдерживаемый кошмар.
Джордан Гудман разобрал типичные анти-паттерны, которых стоит избегать:
- использовать CASE вместо нормальных таблиц,
- вызывать функции на индексированных колонках,
- злоупотреблять DISTINCT, чтобы “починить” дубли.
Подробности — в его статье
👉 @SQLPortal
Джордан Гудман разобрал типичные анти-паттерны, которых стоит избегать:
- использовать CASE вместо нормальных таблиц,
- вызывать функции на индексированных колонках,
- злоупотреблять DISTINCT, чтобы “починить” дубли.
Подробности — в его статье
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤5👍5
This media is not supported in your browser
VIEW IN TELEGRAM
В копилку полезного: принёс ещё одну огромную базу бесплатных API. Внутри аж 1511 штуки на любой вкус: от игр и погоды до финансов и здоровья
Забираем здесь✌️
👉 @SQLPortal
Забираем здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍5❤4
SQL тренажеры для практики
- sql-academy.org
- sql-ex.ru
- schoolsw3.com
- SQL Fiddle
- sqltest.online
- Oracle LiveSQL
- stratascratch.com
- stepik.org (Интерактивный тренажер SQL)
- sql-practice.com
- pgexercises.com
- HackerRank
- sqlzoo.net
👉 @SQLPortal
- sql-academy.org
- sql-ex.ru
- schoolsw3.com
- SQL Fiddle
- sqltest.online
- Oracle LiveSQL
- stratascratch.com
- stepik.org (Интерактивный тренажер SQL)
- sql-practice.com
- pgexercises.com
- HackerRank
- sqlzoo.net
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍8❤3
Postgres реализует MVCC с помощью метаданных транзакций на уровне каждой строки.
Каждая строка , которую ты вставляешь в таблицу Postgres, содержит xmin и xmax. xmin - это ID транзакции, создавшей строку, xmax - транзакции, которая обновила или удалила её.
Когда строка обновляется, Postgres не переписывает её на месте. Он создаёт новый tuple с полной копией данных. В старой версии ставит xmax равным ID транзакции, которая сделала апдейт, а в новой - xmin этой же транзакции.
Какую версию строки увидит транзакция, зависит от её собственного ID и уровня изоляции.
Этот механизм позволяет разным транзакциям видеть разные версии данных, что довольно удобно. Но есть и обратная сторона: старые версии строк накапливаются и раздувают таблицу. Чтобы очистить всё это добро, Postgres нужен VACUUM. Со временем приходится прогонять VACUUM (FULL) или использовать утилиты вроде pg_repack, чтобы вернуть место.
👉 @SQLPortal
Каждая строка , которую ты вставляешь в таблицу Postgres, содержит xmin и xmax. xmin - это ID транзакции, создавшей строку, xmax - транзакции, которая обновила или удалила её.
Когда строка обновляется, Postgres не переписывает её на месте. Он создаёт новый tuple с полной копией данных. В старой версии ставит xmax равным ID транзакции, которая сделала апдейт, а в новой - xmin этой же транзакции.
Какую версию строки увидит транзакция, зависит от её собственного ID и уровня изоляции.
Этот механизм позволяет разным транзакциям видеть разные версии данных, что довольно удобно. Но есть и обратная сторона: старые версии строк накапливаются и раздувают таблицу. Чтобы очистить всё это добро, Postgres нужен VACUUM. Со временем приходится прогонять VACUUM (FULL) или использовать утилиты вроде pg_repack, чтобы вернуть место.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍4❤3
Логирование медленных запросов в Postgres: ставишь
После этого в лог попадут все запросы, которые выполняются дольше двух секунд. Отличный способ быстро вычислить узкие места.
Предварительные условия: logging_collector должен быть включён (on), а log_destination настроен на stderr или другой приемник.
👉 @SQLPortal
log_min_duration_statement = '2s'После этого в лог попадут все запросы, которые выполняются дольше двух секунд. Отличный способ быстро вычислить узкие места.
Предварительные условия: logging_collector должен быть включён (on), а log_destination настроен на stderr или другой приемник.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4
Красота партиционирования.
Партиционирование делит большую таблицу по горизонтали по колонке ключа партиции: все строки с одним и тем же ключом оказываются в своей отдельной таблице, которую и называют партицией.
Логически это всё ещё та же таблица, но при запросах база понимает, в какую партицию лезть, если ключ партиции указан в where.
Такой подход даёт серьёзный прирост производительности и масштабируемости. Можно держать старые партиции, к которым почти не обращаются, на обычных HDD, а свежие — на быстрых SSD.
На каждую партицию можно вешать свои индексы, и они будут куда компактнее, чем один монолитный индекс на всю таблицу.
И к тому же можно убрать целую партицию одной командой, вместо того чтобы удалять строки вручную.
👉 @SQLPortal
Партиционирование делит большую таблицу по горизонтали по колонке ключа партиции: все строки с одним и тем же ключом оказываются в своей отдельной таблице, которую и называют партицией.
Логически это всё ещё та же таблица, но при запросах база понимает, в какую партицию лезть, если ключ партиции указан в where.
Такой подход даёт серьёзный прирост производительности и масштабируемости. Можно держать старые партиции, к которым почти не обращаются, на обычных HDD, а свежие — на быстрых SSD.
На каждую партицию можно вешать свои индексы, и они будут куда компактнее, чем один монолитный индекс на всю таблицу.
И к тому же можно убрать целую партицию одной командой, вместо того чтобы удалять строки вручную.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9😁3
Новый релиз duckdb получился мощным: завезли поддержку Iceberg для INSERT, UPDATE и DELETE.
duckdb можно встраивать куда угодно, так что его реально запускать прямо внутри Postgres, в Edge Functions, в API-серверах и в прочих местах.
👉 @SQLPortal
duckdb можно встраивать куда угодно, так что его реально запускать прямо внутри Postgres, в Edge Functions, в API-серверах и в прочих местах.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4🤔2
Топ причин, почему Postgres не использует индекс:
Его просто нет.
WHERE отбирает больше 5–10% строк. В такой ситуации Postgres выбирает последовательное сканирование, потому что накладные расходы на работу с индексом будут выше.
Планировщик работает со старыми статистиками. Такое бывает после массовой вставки, крупных UPDATE/DELETE, долгого отсутствия VACUUM или при недавно созданных индексах.
Таблица слишком маленькая. Последовательное сканирование в таком случае быстрее, чем использование индекса с его оверхедом.
Несовпадение типа индекса или использование функций над колонками, по которым есть индекс. Например LOWER(email).
Так что если планировщик не использует индекс — почти всегда он делает это потому, что так дешевле по стоимости запроса.
Надеюсь, пригодится.
👉 @SQLPortal
Его просто нет.
WHERE отбирает больше 5–10% строк. В такой ситуации Postgres выбирает последовательное сканирование, потому что накладные расходы на работу с индексом будут выше.
Планировщик работает со старыми статистиками. Такое бывает после массовой вставки, крупных UPDATE/DELETE, долгого отсутствия VACUUM или при недавно созданных индексах.
Таблица слишком маленькая. Последовательное сканирование в таком случае быстрее, чем использование индекса с его оверхедом.
Несовпадение типа индекса или использование функций над колонками, по которым есть индекс. Например LOWER(email).
Так что если планировщик не использует индекс — почти всегда он делает это потому, что так дешевле по стоимости запроса.
Надеюсь, пригодится.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍5
Производительность PostGIS: предикаты пересечения и оверлеи. Новая статья от Пола Рэмзи.
В чём разница между булевыми ST_Intersects и ST_Contains и операциями оверлея ST_Intersection и ST_Difference?
Сегодня разберем самые эффективные подходы к выборке объектов внутри других объектов.
Обычно мелкие геометрии обрезаются по границе с помощью ST_Intersection.
Наивный SQL — это обычный spatial join по ST_Intersects:
На небольшом тестовом наборе, как на картинках, запрос выполняется примерно за 14 мс. Это быстро, но задача маленькая, т.е. на больших данных будет заметно медленнее.
Есть простой способ ускорить запрос, используя то, что булевые пространственные предикаты работают быстрее, чем операции пространственного оверлея.
Что это значит?
Булевые пространственные предикаты - это функции вроде ST_Intersects и ST_Contains. Они принимают две геометрии и возвращают true/false в зависимости от результата проверки.
Операции пространственного оверлея . вроде ST_Intersection или ST_Difference - получают две геометрии и генерируют новую.
Предикаты быстрее, потому что могут прерывать проверку заранее (например, если найдены пересекающиеся ребра, значит геометрии пересекаются) и потому что используют оптимизации prepared geometry с кешированием структуры ребер.
Ускорение работы с оверлеями основано на простой идее = многие объекты вообще не нужно клиппать, если они полностью внутри полигональной границы. Их можно определить с помощью ST_Contains.
Есть и меньшая группа объектов, которые пересекают границу, их уже нужно обрабатывать через ST_Intersection — те, что ST_Intersects, но не ST_Contains.
Более быстрый запрос использует предикаты, чтобы разделить объекты на две категории: полностью внутри (оставляем как есть) и пересекающие границу (клиппим).
Здесь используются два предиката:
– ST_Intersects в join выбирает только кандидатов для обработки
– ST_Contains внутри CASE пропускает геометрии, которые не нужно клиппить
На том же тестовом наборе запрос выполняется примерно за 9 мс - разница настолько заметна, что её видно даже на маленьком примере.
Главная идея = булевые пространственные проверки (ST_Contains, ST_Intersects) значительно дешевле, чем операции вроде ST_Intersection. Обычный подход клиппит все пересекающиеся геометрии. Оптимизированный вариант использует CASE и ST_Contains, чтобы сделать shortcut: если объект полностью внутри. то просто возвращаем его без изменений и не вызываем дорогой ST_Intersection.
Этот шаблон можно применять во всех задачах в PostGIS, где есть клиппинг, spatial join или overlay, и где часть объектов ожидаемо находится целиком внутри границ.
Разделяя данные на два потока — «полностью внутри» (быстрый путь) и «пересекает» (медленный путь), мы гарантируем, что дорогостоящая геометрическая обработка выполняется только там, где она реально нужна.
👉 @SQLPortal
В чём разница между булевыми ST_Intersects и ST_Contains и операциями оверлея ST_Intersection и ST_Difference?
Сегодня разберем самые эффективные подходы к выборке объектов внутри других объектов.
Обычно мелкие геометрии обрезаются по границе с помощью ST_Intersection.
Наивный SQL — это обычный spatial join по ST_Intersects:
SELECT ST_Intersection(polygon.geom, p.geom) AS geom
FROM parcels p
JOIN polygon
ON ST_Intersects(polygon.geom, p.geom);
На небольшом тестовом наборе, как на картинках, запрос выполняется примерно за 14 мс. Это быстро, но задача маленькая, т.е. на больших данных будет заметно медленнее.
Есть простой способ ускорить запрос, используя то, что булевые пространственные предикаты работают быстрее, чем операции пространственного оверлея.
Что это значит?
Булевые пространственные предикаты - это функции вроде ST_Intersects и ST_Contains. Они принимают две геометрии и возвращают true/false в зависимости от результата проверки.
Операции пространственного оверлея . вроде ST_Intersection или ST_Difference - получают две геометрии и генерируют новую.
Предикаты быстрее, потому что могут прерывать проверку заранее (например, если найдены пересекающиеся ребра, значит геометрии пересекаются) и потому что используют оптимизации prepared geometry с кешированием структуры ребер.
Ускорение работы с оверлеями основано на простой идее = многие объекты вообще не нужно клиппать, если они полностью внутри полигональной границы. Их можно определить с помощью ST_Contains.
Есть и меньшая группа объектов, которые пересекают границу, их уже нужно обрабатывать через ST_Intersection — те, что ST_Intersects, но не ST_Contains.
Более быстрый запрос использует предикаты, чтобы разделить объекты на две категории: полностью внутри (оставляем как есть) и пересекающие границу (клиппим).
SELECT
CASE
WHEN ST_Contains(polygon.geom, p.geom) THEN p.geom
ELSE ST_Intersection(polygon.geom, p.geom)
END AS geom
FROM parcels p
JOIN polygon
ON ST_Intersects(polygon.geom, p.geom);
Здесь используются два предиката:
– ST_Intersects в join выбирает только кандидатов для обработки
– ST_Contains внутри CASE пропускает геометрии, которые не нужно клиппить
На том же тестовом наборе запрос выполняется примерно за 9 мс - разница настолько заметна, что её видно даже на маленьком примере.
Суть подхода: комбинируем предикаты и оверлеи через CASE
Главная идея = булевые пространственные проверки (ST_Contains, ST_Intersects) значительно дешевле, чем операции вроде ST_Intersection. Обычный подход клиппит все пересекающиеся геометрии. Оптимизированный вариант использует CASE и ST_Contains, чтобы сделать shortcut: если объект полностью внутри. то просто возвращаем его без изменений и не вызываем дорогой ST_Intersection.
Этот шаблон можно применять во всех задачах в PostGIS, где есть клиппинг, spatial join или overlay, и где часть объектов ожидаемо находится целиком внутри границ.
Разделяя данные на два потока — «полностью внутри» (быстрый путь) и «пересекает» (медленный путь), мы гарантируем, что дорогостоящая геометрическая обработка выполняется только там, где она реально нужна.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1