1

私が理解しているように、SQL Server で 1 つ以上の行を更新すると、レコードが削除され、新しい値で再挿入されます。したがって、これは INSERT イベントがトリガーされることを意味するのでしょうか、それとも行が更新されたときに単に UPDATE がトリガーされることを意味するのでしょうか?

編集:怠惰な読者のために主な情報を強調するには(ただし、以下の davek の回答で完全なリンクの詳細を読むことをお勧めします):

SQL はすべての更新を分割更新として行いますか?

簡単な答えは次のとおりです。

いいえ

少し長い答え:

キー値を変更する更新の場合、SQL はそれらをインプレース更新として行いません。

4

2 に答える 2

4

物理的には挿入/削除として実装されていても、論理的には操作がまだUPDATE.

受け入れられた回答には、キー列の論理更新について話していると見なされた場合、まったく真実ではないフレーズがあります。

キー値を変更する更新の場合、SQL はそれらをインプレース更新として行いません。

これは、一意のインデックスに対する複数行の更新には当てはまりません。これらの SQL Server には、分割/並べ替え/折りたたみ演算子を使用した計画が用意されています。したがって、次の例では、9 回の更新操作が 1 回の削除、8 回の更新、および挿入に変換されます。

CREATE TABLE TestingUpdate7 (
ID INT,
SomeString CHAR(50)
)

CREATE UNIQUE CLUSTERED INDEX idx_ID ON TestingUpdate7 (ID)

INSERT INTO TestingUpdate7 (ID, SomeString)
VALUES
(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),
(5,'Five'),(6,'Six'),(7,'Seven'),(8,'Eight'),(9,'Nine')

CHECKPOINT -- truncate the log, DB is in simple recovery.

UPDATE TestingUpdate7
SET  ID +=1

SELECT Operation, Context, AllocUnitName 
FROM fn_dblog(NULL, NULL) 

戻り値

+-----------------+--------------------+---------------------------+
|    Operation    |      Context       |       AllocUnitName       |
+-----------------+--------------------+---------------------------+
| LOP_BEGIN_CKPT  | LCX_NULL           | NULL                      |
| LOP_XACT_CKPT   | LCX_BOOT_PAGE_CKPT | NULL                      |
| LOP_END_CKPT    | LCX_NULL           | NULL                      |
| LOP_BEGIN_XACT  | LCX_NULL           | NULL                      |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST  | dbo.TestingUpdate7.idx_ID |
| LOP_SET_BITS    | LCX_PFS            | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_MODIFY_ROW  | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_INSERT_ROWS | LCX_CLUSTERED      | dbo.TestingUpdate7.idx_ID |
| LOP_COMMIT_XACT | LCX_NULL           | NULL                      |
+-----------------+--------------------+---------------------------+
于 2012-12-29T14:03:39.320 に答える
3

(削除+挿入への分割)は、更新でインデックスの更新が必要な場合にのみ当てはまると思います。このリンクを参照してください:

http://www.sqlservercentral.com/blogs/sqlinthewild/2011/06/21/are-all-updates-split-into-delete_2D00_insert_3F00_/

特に最後の段落:

現在、分割更新があります。ログに delete_rows 操作と insert_rows 操作があります。これはインプレース アップデートとして行われたものではありません。SQL はすべての更新を分割更新として行いますか? インデックス キーが変更されていない場合、SQL はインプレース更新として更新を実行できることは明らかです。常にそうだと主張するつもりはありませんが、それは愚かなことです。私が見ていないシナリオがたくさんあります (ページ分割と転送された行が最も明白です)。インプレース更新。キー値を変更する更新の場合、SQL はそれらをインプレース更新として行いません。ポールは、しばらく前の彼の暴言の投稿の1つでそれを説明しました – http://sqlskills.com/BLOGS/PAUL/post/Do-changes-to-index-keys-really-do-in-place-updates.aspx

于 2012-09-14T09:33:25.510 に答える