3

一般的な操作は、存在しない場合は新しい行を挿入するか、既存の行を更新することです。残念ながら、SQL ステートメントの挿入と更新の構文は完全に異なります。挿入は列のリストに対応する値のリストを受け取りますが、更新は列=値のペアのリストを受け取ります。MySQL の "insert...on duplicate key update" ステートメント (その upsert ステートメント) は、完全な挿入列/値リストとそれに続く完全な更新列/値リストを必要とするため、この問題を解決しません。[更新: 以下の Wrikken からのコメントは、2 つのステートメントが column=value 構文を共有できることを指摘していますが、他の問題は残っています。]

この問題に関連して、トリガーを使用してデータをチェックする場合 (私のように)、2 つのトリガー (before-insert と before-update) が必要であり、"new" 修飾子を使用する必要があるため、トリガーごとに 1 回ずつ、チェック コードを 2 回記述するか、プロシージャに入れる必要があります。プロシージャを使用する場合は、各列を個別のパラメータとして渡す必要があります。これは、プロシージャが "new" を使用できないためです。これは、多数の列がある場合にエラーが発生しやすくなる可能性があるためです。各列は、create table ステートメントでそのタイプを持っている必要があり、次に、チェック手順の定義で 2 回目のタイプを持っている必要があります。少しのミスで、見つけにくい微妙なバグが作成されます。同じことを 2 回コーディングするアプローチは好きではありません。(これは非正規化に相当します。)

この挿入/更新の問題について考えて、私は次のアイデアをいじっています。特に誰かが実際に試した場合は、フィードバックをお願いします:

最小限のデータのみを保持するプレースホルダー行に対してのみ挿入を使用し、主キーを取得または設定します。次に、ユーザーが入力したすべてのデータを更新ステートメントに入れます。これで、単純な更新のように、「重複キーの更新時に挿入...」は必要ありません。また、挿入時にチェックするものがないため、更新前トリガーでのみデータをチェックする必要があります。(入力フォームからユーザーが提供したすべてのデータは、更新によって処理されますが、挿入によって処理されることはありません。)

もちろん、この方法の主な欠点は、新しい行に対して 2 つの操作があることです。つまり、挿入ではなく、挿入と更新です。ただし、次の理由により、それは要因ではない可能性があります。

  1. 挿入は比較的まれかもしれません。たとえば、私が数年前にリチャードソン (テキサス州) 学区のために行った生徒の採点アプリケーションでは、毎年数千人程度の生徒しか追加されませんでしたが、教師が学年を通しての制度です。

  2. 私が構築した他のいくつかのシステムでは、パフォーマンスは重要ではありませんでした。たとえば、私が取り組んでいる現在のシステムでは、週に数時間だけデータベースを更新する人が 2 人か 3 人しかいません。負荷が非常に小さいため、2 つの操作 (挿入 + 更新) によって発生するオーバーヘッドは、1 つの操作だけで十分な場合に取るに足らないものです。(これは新しい行専用です。覚えておいてください。)

では、実際にこれを試した人はいますか: 最小限のプレースホルダー行を作成するためだけに挿入し、すべてのユーザー提供データの更新に更新を使用しますか?

4

1 に答える 1

7

データベースにデータの有効性に関する「ルール」を強制する必要がある場合でも、UPDATE トリガーだけでなく INSERT トリガーも必要になります。無効なデータを含む INSERT を実行します。とにかく両方のトリガーを持つ傾向があります。

「プレースホルダー」行を挿入してから更新することのもう 1 つの欠点は、(可変長レコードの場合) 断片化の側面があることです。その後の更新では、行の長さが増加することがほぼ保証されます。これにより、データベースの断片化が不必要に増加します (必要な行を挿入しただけでは発生しません)。 )

プレースホルダーの INSERT は成功したが、UPDATE が失敗した場合も考慮する必要があります。その状態を処理するための追加のメカニズムが必要です。

2 つの別個のステートメント (プレースホルダー行を挿入するステートメントと、それを更新するステートメント) を実行するよりも、単一のステートメントを実行して、必要な値を挿入する方が効率的です。

個人的にはINSERT ... ON DUPLICATE KEY UPDATE、私はただ .

INSERT INTO foo (a,b,c) VALUES (1,'one','won'), (2,'two','too')
   ON DUPLICATE KEY
   UPDATE a = VALUES(a)
        , b = VALUES(b)
        , c = VALUES(c)

注: このステートメントの 1 つの副作用に注意してください。特に、それが主UPDATEに実行される場合に注意してください。このステートメントは、挿入しようとする行ごとに AUTO_INCREMENT ID を増やします。生成された値はテーブルに挿入されないため、その AUTO_INCREMENT id 値は本質的に「無駄」になりますが、「なくなります」。(次に生成される値は 1 つ高くなります。)

于 2012-12-12T17:50:56.360 に答える