PostgreSQL Antipatterns: fighting the hordes of "dead" records

The features of PostgreSQL's internal mechanisms allow it to be very fast in some situations and 'not so much' in others. Today, we'll focus on a classic example of the conflict between how the DBMS operates and what developers do with it — UPDATE vs MVCC principles.

A brief plot from an excellent article:

When a row is modified by the UPDATE command, two operations are effectively performed: DELETE and INSERT. In the current version of the row the xmax is set to the transaction number that executed the UPDATE. Then, a new version is created of the same row; the xmin value matches the xmax value of the previous version.

After some time, following the completion of this transaction, the old or new versions, depending on the COMMIT/ROLLBACK, will be recognized as "dead tuples" during a scan VACUUM of the table and cleaned up.

PostgreSQL Antipatterns: fighting the hordes of "dead" records

But this won't happen immediately; issues with 'dead rows' can accumulate very quickly—especially during frequent or bulk updates of records in a large table, and later you may find that even VACUUM cannot help.

#1: I Like To Move It

Let's say your method based on business logic is working fine, and suddenly you realize you need to update field X in a specific record:

UPDATE tbl SET X =  WHERE pk = $1;

Then, as the process continues, it turns out that field Y also needs updating:

UPDATE tbl SET Y =  WHERE pk = $1;

… and then there's Z as well—why not go all out?

UPDATE tbl SET Z =  WHERE pk = $1;

How many versions of this record do we now have in the database? Right, 4 of them! One is current, and you'll need to clean up the other 3 with [auto]VACUUM.

Don't do it this way! Use updating all fields in a single query — you can almost always modify the logic of the method like this:

UPDATE tbl SET X = , Y = , Z =  WHERE pk = $1;

#2: Use IS DISTINCT FROM, Luke!

So, you've decided to update a lot of records in the table (during the application of a script or converter, for instance). And something like this goes into the script:

UPDATE tbl SET X =  WHERE pk BETWEEN $1 AND $2;

This kind of query appears quite frequently and almost always not for filling a new empty field, but for correcting some data errors. However, the correctness of the already existing data is generally not taken into account — and that's a mistake! This means the record is overwritten even if it contained exactly what was intended—why waste effort? Let's fix it:

UPDATE tbl SET X =  WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM ;

Many are unaware of the existence of such a wonderful operator, so here's a cheat sheet on IS DISTINCT FROM and other logical operators to assist:
PostgreSQL Antipatterns: fighting the hordes of "dead" records
… and a bit about operations on complex ROW()-expressions:
PostgreSQL Antipatterns: fighting the hordes of "dead" records

#3: А я милого узнаю по… блокировке

Two identical parallel processes are initiated, each trying to mark the record as 'in progress':UPDATE tbl SET processing = TRUE WHERE pk = $1;

Even if these processes are independently doing different things, with the same ID, the second client will be 'locked' on this query until the first transaction is completed.

Solution #1

: the task is reduced to the previous one.Simply add again

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE; IS DISTINCT FROM:

In this form, the second query will simply not change anything in the database, as everything is already 'as it should be' — therefore, no lock will occur. Next, the fact of the record's 'non-existence' is handled in the application algorithm.

Solution #2

: advisory locksA large topic for a separate article, where you can read about

the methods of application and the pitfalls of advisory locks. Solution #3.

: mindless callsYou should definitely have

simultaneous work on the same record. Delta Chat 1.2 for Android and iOS has been released.? Или вы все-таки накосячили с алгоритмами вызовов бизнес-логики со стороны клиента, например? А если подумать?..

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster