Sql-Server

只需更新一列,觸發更新另一列

  • January 23, 2018

我在我的數據庫中記錄了最慢的查詢,其中一個讓我感到驚訝,它在列表中顯示了很多次,並且通常需要幾秒鐘才能執行。

UPDATE books SET last_read='2018-12-31 11:23:45' WHERE book_id='15'

book_id 是 int identity PK (clustered),last_read 是日期時間。查詢用單引號中的 15 編寫,因此需要轉換,但我無法想像這有什麼大不了的,因為每個查詢只進行一次轉換。表上有 6 個索引,但列 last_read 不涉及或包含在其中任何一個中。PK 在 book_id 上,沒什麼特別的。該表在數據庫中非常重要,包含 50 列和 400,000 行。

估計的執行計劃告訴我:

UPDATE: 0%
Clustered Index Update (on the PK constraint): 100%

該表有一個觸發器 FOR DELETE,我認為這裡無關緊要,還有一個觸發器 AFTER UPDATE,內容如下:

CREATE TRIGGER books_last_update
ON books
AFTER UPDATE
AS
   UPDATE books
   SET last_update = GETDATE()
   WHERE book_id IN (SELECT book_id FROM Inserted)
GO

這向我表明,初始查詢實際上執行了兩個查詢,一個接一個。但是,兩個更新的列都沒有定義索引。我想讓初始查詢執行得更快。

您是否看到任何可能的優化?

恐怕,由於觸發器在 UPDATE 上,並且它實際上更新了列,它可能會觸發多次。可能嗎?如果是,我該如何預防?

book_id 是整數

然後你的程式碼應該說:

WHERE book_id = 15

並不是:

WHERE book_id='15'

在這種情況下,這不應該影響性能,但最好的做法是正確界定(或不界定)。帶單引號的非 Unicode 字元串和日期、以 N 為前綴的 Unicode 字元串、不帶任何引號的二進制和數字。

恐怕,由於觸發器在 UPDATE 上,並且它實際上更新了列,它可能會觸發多次。可能嗎?

不,SQL Server 足夠聰明,不會讓自己跌落懸崖。它認識到觸發器內部的更新不應該在無限循環中遞歸呼叫觸發器。您可以通過執行伺服器端跟踪或擴展事件會話來證明這一點,您將看到觸發器內的更新只執行一次。

您可以添加程式碼以防止該列的更新觸發第二次更新(例如,如果有人手動更新了該last_update列,但這似乎與此處無關)。

您是否看到任何可能的優化?

通常,如果您發現觸發器正在減慢您的程式碼速度(在這種情況下我沒有看到任何證據),請嘗試擺脫觸發器。我不確定是什麼應用程式碼直接更新此表,但如果您可以使用儲存過程來處理對錶的所有更新,那麼您可以將更新添加到該列,而不必依賴觸發器。但是我懷疑如果您等待 5 秒以等待此更新發生,則觸發器不是問題。

引用自:https://dba.stackexchange.com/questions/195989