これは、 SELECT or INSERT
の繰り返しの問題です。 、UPSERTに関連しています(ただし、UPSERTとは異なります)。 Postgres9.5の新しいUPSERT機能は引き続き機能します。
WITH ins AS (
INSERT INTO names(name)
VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO UPDATE
SET name = NULL
WHERE FALSE -- never executed, but locks the row
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM names
WHERE name = 'bob' -- only executed if no INSERT
LIMIT 1;
このようにして、実際に新しい行バージョンを作成する必要はありません。
ただし 、競合状態の小さなコーナーケースはまだあります 。並行トランザクションにより、競合する行が追加された可能性がありますが、同じステートメントにはまだ表示されていません。次に、INSERT
および SELECT
空になります。
単列UPSERTの適切なソリューション:
- 関数内のSELECTまたはINSERTは競合状態になりやすいですか?
バルクUPSERTの一般的なソリューション:
- PostgreSQLでONCONFLICTを使用してRETURNINGを使用するにはどうすればよいですか?
同時書き込み負荷なし
(別のセッションからの)同時書き込みが不可能な場合は、行をロックする必要はなく、単純化できます:
WITH ins AS (
INSERT INTO names(name)
VALUES ('bob')
ON CONFLICT ON CONSTRAINT names_name_key DO NOTHING -- no lock needed
RETURNING id
)
SELECT id FROM ins
UNION ALL
SELECT id FROM names
WHERE name = 'bob' -- only executed if no INSERT
LIMIT 1;