Conditional INSERT with ON CONFLICT in PostgreSQL - Time & Space Complexity
We want to understand how the time taken by a conditional INSERT with ON CONFLICT changes as the data grows.
Specifically, how does the database handle inserting or updating rows when conflicts happen?
Analyze the time complexity of the following PostgreSQL query.
INSERT INTO users (id, name, email)
VALUES (1, 'Alice', 'alice@example.com')
ON CONFLICT (id) DO UPDATE
SET name = EXCLUDED.name,
email = EXCLUDED.email;
This query tries to insert a user. If a user with the same id exists, it updates the name and email instead.
Look for repeated work inside the query execution.
- Primary operation: Checking if the id already exists (conflict check) and then inserting or updating.
- How many times: This happens once per row inserted, but the conflict check may scan an index or table to find duplicates.
As the number of rows in the table grows, the time to check for conflicts depends on how fast the database can find the id.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 3 index comparisons |
| 100 | About 7 index comparisons |
| 1000 | About 10 index comparisons |
Pattern observation: The conflict check uses an index, so operations grow slowly, not linearly.
Time Complexity: O(log n)
This means the time to insert or update grows slowly as the table gets bigger, thanks to the index lookup.
[X] Wrong: "The INSERT with ON CONFLICT always takes the same time no matter how big the table is."
[OK] Correct: The database must check for conflicts using an index, which takes more time as the table grows, but this growth is slow (logarithmic), not constant.
Understanding how conditional inserts work and their time complexity helps you explain database efficiency clearly and confidently in real-world situations.
"What if the table had no index on the conflict column? How would the time complexity change?"
Practice
ON CONFLICT DO NOTHING clause do in a PostgreSQL INSERT statement?Solution
Step 1: Understand ON CONFLICT behavior
TheON CONFLICT DO NOTHINGclause tells PostgreSQL to ignore the insert if a duplicate key conflict happens.Step 2: Compare with other conflict actions
UnlikeDO UPDATEwhich modifies existing rows,DO NOTHINGsimply skips the insert without error.Final Answer:
It skips inserting the row if a conflict occurs on a unique key. -> Option AQuick Check:
ON CONFLICT DO NOTHING = skip insert on duplicate [OK]
- Thinking DO NOTHING updates existing rows
- Assuming DO NOTHING deletes conflicting rows
- Believing DO NOTHING raises an error
id in PostgreSQL?Solution
Step 1: Identify correct ON CONFLICT syntax
PostgreSQL usesON CONFLICT (column) DO UPDATE SETto update on conflict.Step 2: Check syntax details
INSERT INTO table_name (id, val) VALUES (1, 'a') ON CONFLICT (id) DO UPDATE SET val = EXCLUDED.val; correctly usesEXCLUDED.valto refer to the new value and specifies the conflict column.Final Answer:
INSERT INTO table_name (id, val) VALUES (1, 'a') ON CONFLICT (id) DO UPDATE SET val = EXCLUDED.val; -> Option DQuick Check:
ON CONFLICT (id) DO UPDATE SET val = EXCLUDED.val [OK]
- Using MySQL syntax ON DUPLICATE KEY UPDATE
- Omitting conflict target column in ON CONFLICT
- Combining DO NOTHING with SET clause incorrectly
users(id SERIAL PRIMARY KEY, username TEXT UNIQUE, score INT), what will be the result of this query?INSERT INTO users (username, score) VALUES ('alice', 10) ON CONFLICT (username) DO UPDATE SET score = users.score + EXCLUDED.score RETURNING *;Assuming a row with username 'alice' and score 5 already exists.
Solution
Step 1: Understand ON CONFLICT DO UPDATE behavior
The query updates the existing row where username='alice' because of the conflict on username.Step 2: Calculate updated score
The update sets score = users.score + EXCLUDED.score = 5 + 10 = 15, and returns the updated row.Final Answer:
The existing row's score is updated to 15 and returned. -> Option BQuick Check:
ON CONFLICT DO UPDATE adds scores = 15 [OK]
- Thinking a new row is inserted despite conflict
- Expecting an error on duplicate key
- Assuming the row is deleted before insert
products(id INT UNIQUE, name TEXT UNIQUE), identify the error in this PostgreSQL query:INSERT INTO products (id, name) VALUES (1, 'Pen') ON CONFLICT DO UPDATE SET name = EXCLUDED.name;
Solution
Step 1: Check ON CONFLICT syntax
When usingDO UPDATE, PostgreSQL requires specifying the conflict target column or constraint.Step 2: Identify missing conflict target
The query lacks(id)or constraint name afterON CONFLICT, causing syntax error.Final Answer:
Missing conflict target column after ON CONFLICT. -> Option AQuick Check:
ON CONFLICT needs target column for DO UPDATE [OK]
- Omitting conflict target column
- Misusing EXCLUDED keyword
- Assuming WHERE clause is mandatory
email and last_login into a table users(email TEXT UNIQUE, last_login TIMESTAMP). If the email already exists, update last_login only if the new timestamp is more recent. Which query correctly implements this conditional update?Solution
Step 1: Understand conditional update with WHERE clause
PostgreSQL allows aWHEREclause inDO UPDATEto conditionally apply the update.Step 2: Check condition for updating last_login
INSERT INTO users (email, last_login) VALUES ('a@b.com', '2024-01-01') ON CONFLICT (email) DO UPDATE SET last_login = EXCLUDED.last_login WHERE EXCLUDED.last_login > users.last_login; updateslast_loginonly if the new timestamp is greater than the existing one, usingWHERE EXCLUDED.last_login > users.last_login.Final Answer:
INSERT INTO users (email, last_login) VALUES ('a@b.com', '2024-01-01') ON CONFLICT (email) DO UPDATE SET last_login = EXCLUDED.last_login WHERE EXCLUDED.last_login > users.last_login; -> Option CQuick Check:
Use WHERE in DO UPDATE for conditional update [OK]
- Forgetting WHERE clause for conditional update
- Using DO NOTHING with WHERE incorrectly
- Updating unconditionally without checking timestamps
Ready to prove it?
Pass the test and this pattern moves unknown
