Programmingバックエンド開発者

SQLにおけるUPDATE、MERGE、INSERT ... ON DUPLICATE KEY UPDATEの違いについて説明してください。どのアプローチが望ましいのか、またこれらのツールがパフォーマンスとデータの整合性にどのように影響するか。

Hintsage AIアシスタントで面接を突破

答え

SQLはテーブルにデータを更新または挿入するためのさまざまな方法を提供します:

  • UPDATE — 条件に一致する既存のレコードを変更します。
  • MERGE(またはUPSERT) — 挿入と更新のロジックを1つのコマンドに統合します。行が見つかった場合は更新し、見つからなかった場合は追加します。
  • INSERT ... ON DUPLICATE KEY UPDATE(MySQL)または INSERT ... ON CONFLICT DO UPDATE(PostgreSQL) — 新しい行を挿入し、キーの衝突時に既存のものを更新します。

いつ何を使用するべきか:

  • レコードがまだ存在しないことが確実な場合は、INSERTを使用します。
  • 既存のレコードを更新する場合は、条件付きのUPDATEを使用します。
  • レコードが存在するかどうかわからない場合、MERGEまたはUPSERTを使用する方が効果的です。これにより、複雑さが軽減され、SQLリクエストの数が減ります。
  • UPSERT操作は通常、大量のレコードに対してより速く、レース状況を最小限に抑えます。

例(PostgreSQL):

INSERT INTO employees(id, name, salary) VALUES (1, 'Ivan', 100000) ON CONFLICT (id) DO UPDATE SET salary = EXCLUDED.salary;

パフォーマンスと整合性への影響:

  • 個別のUPDATE/INSERTを多数実行すると、レース状況やロックが発生する可能性があります。
  • MERGE/UPSERTは、大量移行時に効果的で、原子性をサポートします。

トリック質問

UPSERTをユニークフィールドに対して実行しようとした際に、同じトランザクションで同じ行を同時に挿入・更新した場合、どうなりますか?

正しい答え: 同じ行を2回変更しようとするため、ロック/衝突エラーが発生する可能性があります。トランザクションは完了しないか、DBMSに応じてdeadlockエラーが発生することになります。

例:

BEGIN; INSERT INTO users(id, name) VALUES (1, 'Oleg') ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name; UPDATE users SET name = 'Petr' WHERE id = 1; COMMIT;

不適切な順序や分離レベルの場合、変更の衝突が発生する可能性があります。


ストーリー №1

データ移行のロジックの中で、SELECTを行い、その後INSERTまたはUPDATEを行う組み合わせを使用していました。結果、他のトランザクションが早くデータを設定し、「duplicate key」エラーが発生することがありました。これにより、夜間のデータエクスポートが頻繁に失敗し、ロジックをUPSERTに変更する必要がありました。


ストーリー №2

MySQLプロジェクトで、ON DUPLICATE KEY UPDATEを不適切に適用しており、複合ユニークキーを正しく考慮していませんでした。その結果、一部のデータが更新されず、重複が発生しました。この問題は本番環境でのみ確認できました。


ストーリー №3

プロジェクトでユーザーデータの同期にUPSERTの代わりにUPDATEを使用していました。接続の障害が発生した際に、新しいユーザーの更新がスキップされるため、一部のデータが失われることがありました。分析の結果、完全にMERGE/UPSERTを導入しました。