r/postgres

▲ 4 r/postgres+1 crossposts

Need advice on postgresql

Hi i have 1.5yr of experience with MS Sql server DB first method, now for a new project i am working with postgressql with Code first method so i have some issues about that, some time when i alter columns from code side and migrate it wont apply and give error like it already in db or somthing like that, when i give it to chat gpt he was suggesting to drop db and create, this not in a live yet but whennit is in live cant drop the table so how you guys handle situations like that?

reddit.com
u/YonduUdonta8 — 1 day ago

How do you handle Postgres schema comparison and drift in 2026?

Hey everyone,

I'm trying to figure out the cleanest way to compare schemas between different PostgreSQL environments (e.g., local dev vs. staging, or staging vs. production).

Every now and then, a quick manual change slips through or a migration script gets applied out of order, and finding the small diffs (missing indexes, subtle column type mismatches, slightly different constraints) becomes a headache.

I know some people rely on feature-rich GUIs like HeidiSQL or SQuirrel SQL for visual diffs, while others prefer dedicated CLI tools or CI/CD pipelines to catch schema drift automatically before it hits prod.

How are you currently handling this?

Do you rely on your GUI's built-in schema diff tool?

Do you use standalone CLI utilities or migration framework checks?

Or do you just treat migrations as immutable and strictly rely on CI checks?

reddit.com
u/Practical_Panic_55 — 2 days ago
▲ 20 r/postgres+1 crossposts

ora2pg переносит ~80% Oracle-схемы. А что происходит с оставшимися 20%?

Если вы хоть раз мигрировали с Oracle на PostgreSQL (или на Postgres Pro Standard/Certified, без лицензии на Enterprise и без проприетарной ora2pgpro), вы наверняка уже знакомы с ora2pg. Это открытый и по-настоящему рабочий конвертер: по независимым оценкам он закрывает в среднем около 80% работы по переносу PL/SQL в PL/pgSQL. Для инструмента, который несколько человек делают в свободное время против коммерческой СУБД с тридцатилетней историей, это очень много.

Проблема не в этих 80%, а в оставшихся 20%. Точнее, в том, как именно они себя ведут.

Молчание вместо ошибки

Когда конвертер не справляется с чем-то синтаксически сложным, он обычно об этом говорит: падает, ругается, пишет ERROR. Неприятно, но честно: о проблеме узнаёшь сразу, в момент конвертации.

ora2pg в самых интересных случаях ведёт себя иначе. Он либо тихо выбрасывает конструкцию, которую не умеет переносить, либо переносит её с багом, который никак себя не проявляет до первого реального вызова в проде. CREATE TABLE при этом отрабатывает без единой ошибки, схема разворачивается, тесты «схема развернулась» зелёные. А дальше как повезёт.

Ниже — пара примеров, каждый прогнан через настоящий ora2pg 25.0 и настоящий PostgreSQL 16, а не пересказан по документации.

READ ONLY таблица. В Oracle это гарантия на уровне сервера: любой INSERT/UPDATE/DELETE в такую таблицу падает с ORA-12081, кто бы ни пытался, хоть владелец схемы.

CREATE TABLE audit_log (
    log_id  NUMBER,
    message VARCHAR2(200)
) READ ONLY;

ora2pg конвертирует это так:

CREATE TABLE audit_log (
    log_id bigint,
    message varchar(200)
) ;

Секция READ ONLY просто исчезла, никакого предупреждения. Проверяем на реальном PostgreSQL:

INSERT INTO audit_log VALUES (1, 'should have been blocked in Oracle');
-- INSERT 0 1

Прошло. В Oracle этот же INSERT был бы гарантированно заблокирован. Если READ ONLY был единственной защитой таблицы-снапшота или архива от случайной записи, после миграции этой защиты просто нет. И никто об этом не узнает, пока кто-нибудь случайно (или не случайно) не запишет туда что-то лишнее.

Баг с двойными скобками в IDENTITY. Тут уже не пропуск конвертации, а самый настоящий баг в подстановке ora2pg.

CREATE TABLE customers (
    customer_id NUMBER GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
    name        VARCHAR2(100)
);

Конвертируется в:

CREATE TABLE customers (
    customer_id bigint GENERATED ALWAYS AS IDENTITY ((START WITH 1 INCREMENT BY 1)),
    name varchar(100)
) ;

Смотрите на ((START WITH.... Лишняя пара скобок, и CREATE TABLE падает уже на загрузке DDL:

ERROR:  syntax error at or near "("

Это самая ранняя по времени проявления находка из всего реестра, даже раньше первого вызова функции. И особенно неприятная, потому что GENERATED ... AS IDENTITY — современный и всё более распространённый способ объявлять auto-increment колонку в Oracle 12c+. Отдельная проверка: без опций в скобках (просто GENERATED ALWAYS AS IDENTITY, без START WITH/INCREMENT BY) конвертируется нормально. Баг именно в обработке опций.

CROSS APPLY. Тут ловушка тоньше. Пакет с процедурой компилируется без единой ошибки, потому что ora2pg просто копирует CROSS APPLY(...) как есть. А PostgreSQL про APPLY вообще ничего не знает, и падает не при деплое, а при первом вызове:

ERROR:  syntax error at or near "APPLY"

Со стороны это выглядит так, будто код развернулся и всё в порядке. А «не в порядке» вылезает только когда кто-то реально дёрнет эту процедуру.

Вот как эти три находки выглядят вместе в отчёте инструмента. Реальный вывод, не мокап:

https://preview.redd.it/1f5k3vx8u2kh1.png?width=1550&format=png&auto=webp&s=9d631ae4006b7d459dc014766e46b0961ecaed85

Откуда уверенность, что это не выдумки

Здесь важна методология, потому что «звучит по-ораклиному специфично» — плохой критерий сам по себе. Часть гипотез, которые интуитивно казались проблемными, на практике не подтвердилась и в реестр не попала. Например, CREATE PACKAGE выглядел очевидным кандидатом на проблемы, но ora2pg переносит его без нареканий.

Правило простое: детектор появляется только после того, как гипотеза подтверждена на практике, а не просто выглядит правдоподобно.

  1. Берётся конкретная Oracle-конструкция.
  2. Собирается минимальный воспроизводимый пример.
  3. Пример прогоняется через настоящий ora2pg.
  4. Результат загружается в настоящий PostgreSQL — смотрим, что получилось на самом деле.
  5. Если справился — гипотеза отклоняется. Если нашёлся воспроизводимый баг — заводится тест-фикстура и пишется детектор.

https://preview.redd.it/webgb0d8u2kh1.png?width=1560&format=png&auto=webp&s=296349970bc9aeebd50743d6d8f6b9a74bba504d

Отдельно все детекторы прогонялись на ~140 тысячах строк реального открытого PL/SQL-кода (пакеты alexandria-plsql-utils и официальные демо-схемы Oracle db-sample-schemas), чтобы убедиться, что они не начинают ложно срабатывать на нормальном коде. Там, кстати, нашлись и настоящие живые попадания. Например, sup_text_idx из официальной Oracle-схемы SH реально использует INDEXTYPE IS CTXSYS.CONTEXT (Oracle Text), которого в PostgreSQL просто нет. Такие находки остаются в проекте постоянными регрессионными тестами: не гипотетический пример, а код, который правда существует.

Забавный момент про сам инструмент

Раз уж рассказ честный, вот ещё одна история. В какой-то момент код-ревью собственных изменений нашёл системный баг в уже выпущенных детекторах. DBMS_METADATA.GET_DDL, стандартный способ выгрузить DDL из Oracle-схемы, по умолчанию не ставит ; в конце оператора. А часть детекторов определяла границу «своего» оператора так: до следующей ;, а если её нет, до конца файла. На несклеенном экспорте это означало, что конструкция из второй таблицы могла по ошибке приписаться первой, если первая шла без точки с запятой.

Починил общим хелпером: он ограничивает оператор либо ближайшей ;, либо началом следующего оператора того же типа, смотря что наступит раньше. Урок простой: даже инструмент, который сам ищет чужие баги, нуждается в таком же скепсисе к себе, как и всё остальное.

Что в итоге

Получился небольшой сканер, не замена ora2pg, а надстройка над ним, которая запускается до миграции. Он смотрит на схему Oracle и для каждой проблемной конструкции показывает: что именно с ней случится, почему, и на что заменить руками. На сегодня в реестре 28 подтверждённых находок, у каждой есть воспроизводимый пример, реальный вывод ora2pg и тесты, включая guard-тесты на ложные срабатывания.

Сама библиотека детекторов — чистый Python без единой внешней зависимости, можно дёргать из своих скриптов вообще без установки чего-либо ещё. У CLI-обёртки одна зависимость, rich, ради приличного терминального вывода.

pip install ora2pg-gap-report
ora2pg-gap-report path/to/schema_dump.pkb another_file.sql

Код и вся доказательная база лежат на GitHub: Lunch418/ora2pg-gap-report, MIT. Если у вас есть своя Oracle-схема с чем-то диким, чего нет в реестре, заводите issue. Мне правда интересно найти это и разобрать так же честно, как всё остальное здесь.

reddit.com
u/VisualActuary1559 — 2 days ago

As a Postgres beginner, what GUI features actually save you time day-to-day?

I’ve recently started working with PostgreSQL on a daily basis. Coming from a background where I mostly interacted with simple databases, the sheer depth of Postgres tools feels a bit overwhelming. I’m trying to avoid just treating my GUI (like pgAdmin, DBeaver, DataGrip, or TablePlus) as a glorified query runner. I know these tools have deep features built specifically for Postgres, but as a beginner, it’s hard to tell what’s actually useful in production versus what’s just a shiny extra. So far, I've found basic visual explain plans somewhat helpful for understanding slow queries, but I feel like I'm barely scratching the surface. For those of you who have been using Postgres for a while: what is one specific feature in your GUI of choice that genuinely saves you time or prevents silly mistakes? Are there built-in UI tools for monitoring locks, schema diffing, or managing connections that you now can't live without?

Would love to hear how experienced engineers set up their workflow!

reddit.com
u/porudentyu — 7 days ago
▲ 3 r/postgres+2 crossposts

Found a file named .odoo_pg_health.json running in my Odoo/Postgres Docker setup. What is this?

Hey everyone,

I was checking my container setup today and noticed some unusual resource usage. Looking closer into the database container, I found a configuration file located at /var/tmp/.odoo_pg_health.json that appears to be related to XMRig.

Here is my current environment setup:

  • Stack: Odoo 15 container with a separate postgres image via Docker Compose.
  • Network/Ports: Only Odoo port 8069 is open to the public internet. The Postgres container port 5432 is strictly internal on a closed Docker network (prod-network) and has no public port mapping.
  • The File: The configuration inside .odoo_pg_health.json lists connections to pool.hashvault.pro:443 and pool.hashvault.pro:80.

Since the Postgres port isn't exposed externally, I'm trying to figure out how this file got here and what it's doing.

Have any of you seen this specific file name (.odoo_pg_health.json) or setup before? What do you guys know about how something like this gets generated or dropped into an isolated container?

Appreciate any thoughts or guidance on what to check next!

reddit.com
u/WhereasBulky5724 — 6 days ago

I've been working on a custom tree index that runs up to 7x faster than LTREE (early benchmarks)

Hi All
I’ve been working on a custom data structure and algorithm for hierarchical indexing.

while I designed the algorithm myself, I wouldn't claim to be a definitive master of hierarchy trees. I'm mainly sharing these early numbers in hopes of connecting with the right people to see if there's genuine value.

I ran benchmarks against 1M and 2M node recursive trees on PG 16. The baseline comparisons against ltree are looking solid:

  • Huge I/O Drop: For descendant queries, B-tree range scans touch up to 74x fewer buffer pages.
  • Query Speed: Subtree queries run 1.0x to 6.7x faster. Ancestor lookups (via SP-GiST) execute up to 7.3x faster.
  • Storage Density: A custom compact encoding shrank the on disk value size by 42.7%. This translates to a ~23% smaller B-tree index footprint.
  • Write Performance: Appending 50,000 leaf nodes is roughly 2x faster. Reparenting large subtrees is 1.2x to 2.7x faster

I have some thoughts where this may be beneficial but lacking some subject matter expertise when it comes to practical application of hierarchy data.
- Could it make servers run more efficiently?
- Do other more efficient extensions/algos beat these benchmarks? Is LTREE just a default?
- What kinds of large scale operations would this benefit? Domains/applications?
- What should my benchmark tests look like?

Eager to get some expert opinions and either validate my thoughts or give me some reality - cheers!

reddit.com
u/Capital-Currency9045 — 7 days ago
▲ 1 r/postgres+1 crossposts

Self made Postgres clients OSS

Hi all, hopefully this does not break any rules, I see some posts here requesting for new Postgres clients I made one and ended up releasing a local lightweight webapp version of my app today. It’s not the best or replaces pgadmin but works well for me.

It’s this one https://github.com/FrancisTCE/gresui-web.

Do you have your own Postgres client tools? I would like to see where I can improve this, it’s useful for me as well see what you got if you want to share.

u/BassIs4StringDrum — 7 days ago
▲ 70 r/postgres+1 crossposts

Anyone who works on a production Postgres knows the feeling. Every command you run, you're walking a tightrope. One typo, one wrong terminal tab, one bug in the app that turned a filter into a full-table query, and now you're doing PITR or restoring from backup at 3am.

I've spent years as a DBA in charge of critical production workloads. Most of the time the rope holds. Sometimes it doesn't.

pg_savior is a Postgres extension that hooks the planner and refuses the obvious dangerous shapes:

  • DELETE / UPDATE without a WHERE
  • CREATE INDEX without CONCURRENTLY
  • DROP DATABASE
  • ALTER COLUMN TYPE that triggers a full rewrite
  • DELETE WHERE id > 0 (planner row estimate gives intent away)

When you really mean it: SET LOCAL pg_savior.bypass = on for the transaction, and the guard steps aside.

It's an extension, not a proxy — psql against a local socket, ORMs, migration tools, cron jobs, AI agents with DB credentials all hit the same hook. Nothing routes around it.

Three hooks do the work: post_parse_analyze_hook, ExecutorStart_hook, ProcessUtility_hook.

What other dangerous queries should pg_savior catch? Also, curious if you have best practices to catch these mistakes.

u/vira28 — 12 days ago
▲ 24 r/postgres+2 crossposts

The dangers of Postgres subtransactions

Has anyone encountered subtransaction overflow in production? This was an awesome article to read but I haven't experienced it yet.

Wonder how many hairs I would have ripped out.

planetscale.com
u/Wooden-News-962 — 9 days ago
▲ 6 r/postgres+2 crossposts

How do you handle slow queries when there's no DBA on the team?

Hey all -

Been doing database performance work (mostly Postgres/MySQL) for over a decade, and I keep running into the same situation with small teams: no dedicated DBA, but queries are slowing things down as the product grows.

Curious how people here actually deal with it in practice. Do you just wait until something breaks and then dig into EXPLAIN plans yourself? Does one dev end up becoming the "unofficial DBA" by default? Do you use any monitoring tool, or is it mostly guesswork?

Not selling anything, genuinely trying to understand how painful (or not) this actually is for teams without dedicated DB expertise, and what you wish existed to make it easier.

reddit.com
u/Away-Structure-5222 — 12 days ago
▲ 2 r/postgres+1 crossposts

Benchmarked FSx for OpenZFS for Postgres: 8x provisioned throughput bought +29% TPS; 3x IOPS bought 2.5x

We run development Postgres databases on FSx for OpenZFS and wanted to know which of its two billing knobs — provisioned throughput or provisioned SSD IOPS — actually buys Postgres performance. Throughput is the expensive lever on FSx pricing; IOPS is the cheap one.

Method: one 256 GiB SINGLE_AZ_1 filesystem, one Postgres (CloudNativePG) database on it, pgbench scale 50 (5,000,000 accounts). We stepped the filesystem through six tier combinations in place with aws fsx update-file-system (non-disruptive, ~2–10 min per step) and re-ran pgbench against the same database at every tier: 4 clients / 2 threads / 60 s, select-only (-S) and TPC-B.

Tier (MB/s / IOPS) select-only TPS TPC-B TPS TPC-B avg latency
128 / 1000 15,272 645 6.21 ms
256 / 1000 16,361 699 5.72 ms
512 / 1000 15,398 769 5.20 ms
1024 / 1000 15,770 834 4.80 ms
1024 / 3000 15,865 2,089 1.92 ms
128 / 3000 14,556 1,925 2.08 ms

What we took from it:

  1. Throughput scaling barely matters for OLTP. 8x the provisioned throughput (128 → 1024 MB/s) bought +29% TPC-B TPS. The workload is bound by sync-write latency per operation (WAL fsyncs), not bandwidth.
  2. Provisioned IOPS is the knob that matters. 3x IOPS at fixed throughput took TPC-B from 834 to 2,089 TPS (2.5x) and cut latency 4.8 → 1.9 ms.
  3. The cost-optimal shape is cheap throughput + provisioned IOPS. 128 MB/s with 3000 IOPS hit 1,925 TPS — 92% of the best result we measured — at the lowest throughput tier.
  4. Read-heavy work was insensitive to both knobs (~15–16k TPS across every tier): the hot set lives in shared buffers/page cache and CPU is the ceiling.

Caveats before anyone over-indexes on this: single 60 s run per tier (no variance estimate), a small hot set (a working set larger than RAM would move the read numbers, though not the WAL-fsync conclusion), one database with no concurrent cluster load, SINGLE_AZ_1 in us-east-2, July 2026.

Full write-up with method details and the sizing implications: https://stagdb.com/blog/fsx-openzfs-postgres-throughput-iops/

Happy to answer questions or re-run with different parameters if there's something specific you'd want tested.

u/observantwallflower — 13 days ago