Sql-Server

SQL Server 中的觸發器與作業

  • April 17, 2019

我正在設計一個帶有表的數據庫,該表每 15 秒自動載入一條新記錄(每條記錄將有一個“時間戳”欄位和大約 50 個“浮點”欄位)。此表中的每條記錄都需要復製到另一個表中。我已經使用兩種不同的方法進行了一些初步測試:

  1. 使用觸發器將每條記錄插入另一個表(每次將記錄添加到源表時觸發 - 每 15 秒)
  2. 使用一個作業(SQL Server 代理)每隔十分鐘左右執行一次,並將一批記錄插入到另一個表中(並使用源表中的標誌欄位來指示哪些記錄已被處理)。

我對觸發器或 SQL Server 作業沒有太多經驗,所以我不知道對成本和系統資源的影響(隨著時間的推移,兩個表都會有很多記錄)。

一般來說,什麼方法會更好?我應該考慮另一種方法嗎?

謝謝

每 15 秒插入一條記錄時,我不會擔心使用觸發器。

考慮這兩個堆表,每個有 1rowversion列和 50float列。

CREATE TABLE dbo.floattable1
(Rowver ROWVERSION
,Float1    float
,Float2    float
...);
CREATE TABLE dbo.floattable2
(Rowver ROWVERSION
,Float1    float
,Float2    float
...);

兩個表都有**~2M**行 (1940480)。

帶觸發器的解決方案

當我們創建一個AFTER INSERT TRIGGERondbo.floattable1也插入到dbo.floattable2

CREATE TRIGGER dbo.floattrigger
ON dbo.FloatTable1
AFTER INSERT
AS
INSERT INTO dbo.floattable2(Float1    ,Float2     ,Float3     ,Float4     ,Float5     ,Float6     ,Float7     ,Float8     ,Float9     
,Float10  ,Float11  ,Float12  ,Float13  ,Float14  ,Float15  ,Float16  ,Float17  ,Float18  ,Float19  ,Float20  ,Float21  ,Float22  
,Float23  ,Float24  ,Float25  ,Float26  ,Float27  ,Float28  ,Float29  ,Float30  ,Float31  ,Float32  ,Float33  ,Float34  ,Float35  
,Float36  ,Float37  ,Float38  ,Float39  ,Float40  ,Float41  ,Float42  ,Float43  ,Float44  ,Float45  ,Float46  ,Float47  ,Float48  ,Float49  ,Float50 )
SELECT Float1     ,Float2     ,Float3     ,Float4     ,Float5     ,Float6     ,Float7     ,Float8     ,Float9     ,Float10  ,Float11  ,Float12  ,Float13  
,Float14  ,Float15  ,Float16  ,Float17  ,Float18  ,Float19  ,Float20 ,Float21  ,Float22  ,Float23  ,Float24  ,Float25  ,Float26  ,Float27  ,Float28  ,Float29  
,Float30  ,Float31  ,Float32  ,Float33  ,Float34  ,Float35  ,Float36  ,Float37  ,Float38  ,Float39  
,Float40  ,Float41  ,Float42  ,Float43  ,Float44  ,Float45  ,Float46  ,Float47  ,Float48  ,Float49  ,Float50 
FROM inserted;

之後,我們插入一整行dbo.floattable1導致觸發器執行:

在此處輸入圖像描述

還有一個非常簡單的計劃,只有 1 次邏輯讀取。

作業解決方案 / FlagColumn

放下觸發器,添加一個標誌列,將其設置為 1 並在其上添加一個索引。

DROP TRIGGER  dbo.floattrigger;
ALTER TABLE dbo.floattable1 
ADD FlagColumn bit;
UPDATE dbo.floattable1 SET FlagColumn = 1;

CREATE INDEX IX_FlagColumn on dbo.floattable1(FlagColumn);

插入 40 條測試記錄,flagcolumn = 0

SET STATISTICS IO, TIME ON;
INSERT INTO dbo.floattable1(Float1    ,Float2     ,... ,FlagColumn)
SELECT TOP(40) Float1     ,Float2     ,... , 0
FROM dbo.floattable1

插入 dbo.floattable2 並更新標誌列

BEGIN TRANSACTION
INSERT INTO dbo.floattable2
(Float1   ,Float2     ,...)
SELECT Float1     ,Float2     ,...
FROM dbo.floattable1 
WHERE FlagColumn = 0;

UPDATE dbo.floattable1 
SET FlagColumn = 1
WHERE FlagColumn = 0;
COMMIT TRANSACTION

通過刪除 RID 查找(將所有浮點數添加到索引的包含列列表),可以將第一個插入改進為等於觸發器的插入。

在此處輸入圖像描述

但是更新會帶來一些額外的成本。

在此處輸入圖像描述.

您在這裡的優勢是您可以在需要時安排此操作,並通過標誌獲得有關數據的更多資訊。額外的索引意味著額外的成本,Insert+Update意味著額外的成本,而不是僅僅發出Insert.


這兩種想法都是可行的,但這實際上取決於使用表格的複雜程度/簡單程度。如果它僅用作記錄表,並且觸發器將每 15 秒觸發一條記錄(僅此而已),那麼觸發器應該沒問題。如果數據同步不需要那麼快/經常發生,那麼帶有INSERT+的數據載入UPDATE也應該沒問題。YMMV,始終在實施前進行測試。

考慮到這一點,

假設每 15 秒插入 5 條記錄(超過 1 條記錄)。然後Trigger將針對那些多行觸發。這意味著許多數據庫日誌

另一方面,Jobs將在單個事務中插入這 5 條記錄,從而減少數據庫日誌的輸入。

所以在某些情況下Trigger資源比Jobs.

如果每 15 秒插入一條記錄,並且在任何其他表中沒有發生其他插入或事務,則Trigger可以接受。

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