From 2f8962ceff6c484cc8a7a96322c55ba53623954a Mon Sep 17 00:00:00 2001 From: Victor Lyuboslavsky Date: Tue, 30 Apr 2024 11:29:43 -0500 Subject: [PATCH] Updated `Insert on duplicate update` section. (#18607) #16562 Doc update to reflect recent deadlock fix. --- handbook/engineering/scaling-fleet.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handbook/engineering/scaling-fleet.md b/handbook/engineering/scaling-fleet.md index c8fc23f77a..03cdd5e2b9 100644 --- a/handbook/engineering/scaling-fleet.md +++ b/handbook/engineering/scaling-fleet.md @@ -49,6 +49,8 @@ It’s very important to understand how a table will be used. If rows are insert This approach has a caveat. It introduces a race condition between the `UPDATE` and the `INSERT` where another `INSERT` might happen in between the two, making the second `INSERT` fail. With the right constraints (and depending on the details of the problem), this is not a big problem. Alternatively, the `INSERT` could be one with an `ON DUPLICATE KEY UPDATE` at the end to recover from this scenario. +When using transactions, the above `INSERT` race condition may [cause a deadlock](https://victoronsoftware.com/posts/mysql-upsert-deadlock/). The simplest solution is to retry the failing transaction. However, another solution may be needed if such deadlocks happen too often. + This is subtle, but an insert will update indexes, check constraints, etc. At the same time, an update might sometimes not do any of that, depending on what is being updated. While not a performance GOTCHA, if you do use `INSERT … ON DUPLICATE KEY UPDATE`, beware that LastInsertId will return non-zero only if the INSERT portion happens. [If an update happens, the LastInsertId will be 0](https://github.com/fleetdm/fleet/blob/1aff4a4231ccff4d80889b46b57ed12c5ba1ae14/server/datastore/mysql/mysql.go#L925-L953).