Comparison Between Odoo Transient Models and PostgreSQL Persistence

Relpersistence in PostgreSQL 

In PostgreSQL, every relation (table, index, sequence, etc.) is tracked in pg_class.

The column relpersistence tells PostgreSQL how long that object is supposed to live.

These are the only possible values:

  • P - permanent: It mainly specifies the normal tables, indexes, and sequences
  • t - temporary: Session-local objects (CREATE TEMP TABLE). Dropped automatically when the session ends.
  • U - unlogged: Like permanent tables, but no WAL logging. Faster, but truncated after crash/restart.

When we create a normal table or transient table through the Odoo ORM method, the value of relpersistence will be ‘p’.

That’s exactly what we find it from our postgres research in the Odoo database

Example check:

SELECT relpersistence,*
FROM pg_class
WHERE relname = 'sale_order';

Result:

-[ RECORD 1 ]-------+-----------
relpersistence      | p
oid                 | 5309786
relname             | sale_order
relnamespace        | 2200
reltype             | 5309788
reloftype           | 0
relowner            | 16389
relam               | 2
relfilenode         | 5309786
reltablespace       | 0
relpages            | 0
reltuples           | -1
relallvisible       | 0
reltoastrelid       | 5309790
relhasindex         | t
relisshared         | f
relpersistence      | p
relkind             | r
relnatts            | 43
relchecks           | 1
relhasrules         | f
relhastriggers      | t
relhassubclass      | f
relrowsecurity      | f
relforcerowsecurity | f
relispopulated      | t
relreplident        | d
relispartition      | f
relrewrite          | 0
relfrozenxid        | 1037326
relminmxid          | 4109
relacl              | 
reloptions          | 
relpartbound        | 

Why “transient tables” in Odoo do not mean temporary in PostgreSQL

While working on database internals and inspecting pg_class, an interesting pattern appears when analyzing Odoo’s so-called transient tables.

At first glance, the name suggests PostgreSQL temporary tables.

But the catalog tells a different story.

Let’s walk through what actually happens.

What PostgreSQL considers temporary

In PostgreSQL, a true temporary table:

  • Lives in a session-specific schema (pg_temp_xxx)
  • Has relpersistence = 't'
  • Disappears automatically when the session closes
  • Is invisible to other sessions

These objects are fully managed by PostgreSQL itself.

You can detect them with:

SELECT c.relname, c.relpersistence, n.nspname
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname LIKE 'pg_temp%';

Only tables with relpersistence = 't' qualify as real temporary tables.

Just create a temporary table in postgresql and check again the above query

create TEMP TABLE demo_table(id int,name text);

Result:

-[ RECORD 1 ]--+----------
relname        | demo_table
relpersistence | t
nspname        | pg_temp_5

What Odoo calls “transient”

In Odoo, models that inherit from TransientModel are often described as temporary.

However, when you inspect these tables inside PostgreSQL, you’ll find:

  • They live in normal schemas (usually public)
  • They show relpersistence = 'p'
  • They behave exactly like regular tables at the storage level

From PostgreSQL’s perspective, they are fully permanent relations.

There is no special flag, catalog type, or storage optimization applied.

So where does the “temporary” behavior come from?

Not from PostgreSQL.

Odoo enforces this lifecycle at the application layer:

  • Records are created like any other row
  • Periodic cleanup jobs delete old entries
  • Some models auto-purge based on age
  • Developers explicitly remove rows after wizard completion

In other words:

PostgreSQL stores the data permanently, and Odoo decides when to erase it.

Why this matters for performance research

If you are tuning PostgreSQL for Odoo workloads:

  • These transient tables still generate WAL
  • They still consume buffer cache
  • They still participate in vacuum
  • They still affect bloat and index growth

They are not lightweight temp objects.

Treating them as real tables is essential when:

  • Analyzing write amplification
  • Investigating vacuum pressure
  • Measuring storage churn
  • Designing custom PostgreSQL optimizations

Your catalog inspection confirms this clearly:

relpersistence = 'p' proves Odoo transient models are logical temporaries, not physical ones.

PostgreSQL defines persistence at the engine level.

Odoo defines “transient” purely at the framework level.

They solve different problems.

Understanding this boundary helps avoid incorrect assumptions during database tuning and source-level experimentation.

whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, KINFRA Techno Park
Kakkanchery, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message