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
❤4👍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