AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

A generated-column mode chooses when computation is paid

PostgreSQL 18 makes virtual generated columns the default. Choose read-time or write-time calculation explicitly, within each mode’s expression restrictions.

Citiți articolul în română

A generated column gives a derived value a place in the schema. Choosing its mode also decides when the database pays to calculate that value. Virtual columns move that work to reads; stored columns calculate on writes and retain the result. Name the choice explicitly when it expresses an important workload assumption, rather than allowing a default to stand in for a design decision.

In this November 2026 retrospective, the historical prompt is PostgreSQL 18 beta 2, announced on 17 July 2025. That was an invitation to test representative workloads, with an explicit warning against production use of the beta. It was not the first announcement of virtual generated columns and not the stable release of PostgreSQL 18.

Separate the preview from the final contract

The 8 May beta 1 announcement already listed virtual generated columns among planned features. The version 18 release notes give the stable release date as 25 September 2025. Keeping those dates separate lets a retrospective use final documentation without pretending its completed contract was already a stable July release.

The version 18 generated-column documentation, consulted in November 2026, describes virtual as the default. VIRTUAL and STORED make the mode explicit. The documentation is pinned to a major version, but it remains maintained documentation rather than a frozen copy of the July beta manual.

A default is useful for concise definitions. Explicit mode selection is useful when future readers need to understand where work belongs. Neither choice proves a performance advantage. The database can define the mechanism, while only the application's query and write patterns establish whether that mechanism serves the product well.

The cost follows the use of the value

Consider an illustrative table with a base measurement and a derived unit conversion. A virtual definition can express the conversion without retaining a second value in the row. If the derived field is seldom requested, calculating it at read time may be attractive. The rationale is that the stored representation need not include that derived value, not that every query becomes faster.

Now consider a derived expression that is expensive and requested repeatedly. Paying for it when rows are written may be preferable to recalculating it for reads. A stored column has a storage cost and a write-time calculation cost, but those costs can be reasonable when they support the important read path. This is workload reasoning, not a local measurement of either mode.

Read frequency alone is insufficient. Ask which reads actually request the derived value and how that demand relates to changes in the base data. An operational screen that rarely needs the value creates a different trade from a repeated export that depends on it. A single ratio across all database activity can hide the query family that matters most to users.

The same caution applies to storage. The documentation's statement that a virtual generated column occupies no storage describes the column value. It is not a measured claim about the total size of a particular deployment. Other schema objects and the surrounding workload still matter. This article reports no database execution, size comparison or performance result.

Expression restrictions can decide the mode first

Both modes have restrictions on the generation expression. Version 18 requires immutable functions, no subqueries and no references outside the current row. Another generated column cannot be referenced. System columns are excluded except for tableoid. A generated column also cannot have a default or identity definition, or form part of a partition key.

Virtual columns add an important restriction: their types cannot be user-defined, and their expressions cannot refer to user-defined functions or types, including indirectly through operators or casts. Stored columns do not have that additional restriction. These are schema eligibility conditions, not merely tuning advice. A workload argument cannot make an unsupported expression valid.

For a proposed schema change, examine the expression before estimating savings. A conversion using ordinary built-in operations is a different case from a business calculation encoded in a custom function. If the latter is not eligible for virtual generation, the team needs another design or a stored definition that satisfies its own requirements.

Immutability also limits what the field can mean. A derived value based on the current time or on another table's changing state is not an ordinary eligible generation expression. Treating such a value as if it were a deterministic function of the row would misdescribe the business rule. The appropriate design may require a query, a maintained summary or another explicit update mechanism.

Generated columns should also be distinguished from defaults. A default supplies a value when a row is inserted without one; a generated value is computed under its generation rule and cannot be overridden by an ordinary supplied value. That distinction matters when an import process expects to submit its own authoritative result. A schema change can alter the application's write contract even when the field name stays familiar.

Keep the decision tied to one derived field

A useful evaluation proposal names the exact expression, queries and writes being compared. It should preserve representative input distributions and request patterns. If the product depends on first-screen latency, include that path; if the value mainly appears in batch reports, evaluate that use instead. These are suggested checks for an authorized environment, not tests performed for this article.

The strongest counterargument to explicit selection and evaluation is simplicity. A cheap eligible expression, used infrequently in a modest workload, may fit the virtual default without an elaborate study. That is reasonable when the owner understands the assumptions. The point is to make the decision proportionate, not to require a benchmark for every schema line.

A costly, frequently read expression warrants a different discussion. Retaining STORED can be an intentional purchase of predictable read work rather than resistance to a new feature. Equally, retaining a derived value that is almost never read may deserve reconsideration. Neither mode is a general instruction to optimize every field in the same direction.

For custom software development, include the chosen mode and the workload assumption in the schema review. This differs from deciding whether skip scan can replace an index: here the question is when a derived value is computed and whether its expression is eligible. Revisit that choice when the product's use of the field changes, with evidence about the actual path being served.