1

据我了解,当您更新 SQL Server 中的一行或多行时,该记录将被删除并重新插入新值。因此,这是否意味着触发了 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 不会将其作为就地更新进行。保罗在不久前的一篇揭穿文章中解释说——http: //sqlskills.com/BLOGS/PAUL/post/Do-changes-to-index-keys-really-do-in-place-updates.aspx

于 2012-09-14T09:33:25.510 回答