Upsert
Inserting a row if it doesn't exist and updating it if it does, in one atomic statement, which is harder than it sounds because the obvious check-then-insert version races with itself.
An upsert writes a record by inserting it if it doesn't exist yet and updating it if it does. The word blends "update" and "insert." It is the natural operation for syncing data from elsewhere, loading a pipeline's output, or keeping a running count.
The obvious implementation is wrong. Code that first checks whether the row exists and then inserts or updates leaves a gap between the two steps. Two clients can both check, both find nothing, and both insert, producing a duplicate or an error. It is a textbook Race Condition of the Time-of-Check to Time-of-Use kind. A real upsert has to be a single atomic operation inside the database.
That requires a definition of "already exists," which comes from a unique Database Constraint on some column or set of columns, often a natural key such as an email address or an ID from an outside system. Databases spell it differently:
- PostgreSQL (since 2016) and SQLite use
INSERT ... ON CONFLICT (key) DO UPDATE, with the proposed row available asEXCLUDED. - MySQL uses
INSERT ... ON DUPLICATE KEY UPDATE. - The SQL standard has
MERGE, which matches a source table against a target and applies different actions to matched and unmatched rows. It is powerful for bulk loads, but some implementations aren't safe under concurrency without extra locking. - Key-value stores usually make every write an upsert, since putting a value at a key overwrites whatever was there.
Several details catch people out:
- Replace is not update. SQLite's and MySQL's
REPLACEdelete the old row and insert a new one, which fires delete triggers, cascades through foreign keys, and resets any columns not supplied. - Stale overwrites. An upsert from a slow, out-of-order source can overwrite newer data with older. A condition such as "update only if the incoming timestamp is newer" prevents it; see Optimistic Locking.
- Sequence gaps. Databases often reserve an auto-increment ID before discovering the conflict, so IDs skip numbers. That is harmless but surprises people who expected them to be contiguous.
- Deadlocks. Two large batches that upsert the same keys in different orders can deadlock. Sorting each batch by key first avoids it.
Upserts are what make a sync job safe to rerun. Running the same load twice leaves the same result, so a failure halfway through needs no cleanup; see Idempotence and ETL Pipeline. They also fit streams of changes copied from another database, where each event says what a row should now contain; see Change Data Capture.
ORMs often offer a findOrCreate or upsert method. Some implement it as the racy check-then-insert, so it is worth reading what SQL they actually send; see Object-Relational Mapping.
See also2
Idempotency Key
A unique token a client attaches to a request so the server can recognize a retry and return the original result instead of doing the work twice, the standard defense against double charges and duplicate orders.
Data & Content10 connections
SQL
The declarative language for asking questions of relational databases, designed at IBM in the 1970s, standardized in 1986, repeatedly declared obsolete and still the most widely used way to read and write structured data.
Data & Content9 connections
Linked from9
- Change Data CaptureData & Content
Turning a database's own internal write log into a stream other systems can subscribe to, without touching the application.
- Database ConstraintData & Content
Rules declared in the schema that the database itself enforces on every write, such as uniqueness, required values, and allowed ranges, so bad data is refused at the door rather than cleaned up later.
- ETL PipelineData & Content
The job of pulling data out of operational systems, cleaning and reshaping it, and loading it somewhere it can be analyzed, and the move from transforming before loading to transforming after.
- IdempotenceSystems & Tooling
The property that performing an operation twice has the same effect as performing it once.
- Idempotency KeyData & Content
A unique token a client attaches to a request so the server can recognize a retry and return the original result instead of doing the work twice, the standard defense against double charges and duplicate orders.
- Key-Value StoreData & Content
The simplest kind of database, which stores opaque values under unique keys and supports little more than get, put and delete, trading query power for speed and easy scaling.
- Optimistic LockingData & Content
Letting concurrent writers proceed unchecked and catching conflicts only at commit time, betting that collisions are rare.
- SQLData & Content
The declarative language for asking questions of relational databases, designed at IBM in the 1970s, standardized in 1986, repeatedly declared obsolete and still the most widely used way to read and write structured data.
- Time-of-Check to Time-of-UseSystems & Tooling
A race where a program checks a condition and then acts on it, but the world changes in between, the root of classic file-permission exploits and of double-spending bugs in web applications.