如何修復特定查詢的高 DTU 使用率
我有一個在 Microsoft SQL Azure 數據庫上每隔幾秒鐘執行一次的查詢。它來自一個 Web 作業,該作業檢查是否需要根據特定表(它的排隊表)中的行執行操作。根據所附圖片,是否有人對我如何減少相關查詢的 DTU 使用率有任何建議,它導致數據庫達到 100% CPU。
沒有完整的表定義,我將嘗試一下它可能是什麼。根據您問題中的螢幕截圖,表格可能如下所示:
CREATE TABLE dbo.TaskSchedulerItem ( TaskSchedulerItemID int IDENTITY(1,1), TaskSchedulerID int, ItemStatus varchar(10), DateLastUpdated datetime2(0), CONSTRAINT PK_TaskSchedulerItem PRIMARY KEY CLUSTERED (TaskSchedulerItemID) );
只是為了好玩,讓我們在其中放入一些隨機樣本數據:
INSERT INTO dbo.TaskSchedulerItem (ItemStatus, TaskSchedulerID, DateLastUpdated) SELECT TOP 10 'Pending', column_id, GETDATE() FROM sys.columns UNION ALL SELECT TOP 10000 'Complete', column_id, GETDATE()-1 FROM sys.columns;
現在我們可以針對該數據執行查詢:
DECLARE @CurrentDateTime datetime2(0) = GETDATE(), @TaskSchedulerID int = 4, @TaskSchedulerItemID int; SELECT TOP 1 @TaskSchedulerItemID = TaskSchedulerItemID FROM dbo.TaskSchedulerItem WHERE ( ItemStatus IN ('Pending','Failed') OR ItemStatus = 'IN PROGRESS' AND DateLastUpdated < DATEADD(MINUTE, -1, @CurrentDateTime) ) AND TaskSchedulerID = @TaskSchedulerID ORDER BY DateLastUpdated; SELECT @TaskSchedulerItemID;
我不確定您的查詢是否正在執行聚集索引掃描,但這將是我的猜測。我們只是在尋找一行——理想情況下,我們將能夠對這一行(或者,至少更少的行)進行搜尋。ed 標準使這
OR
有點棘手,因此擁有一個始終為我們提供確切行的單一索引有點具有挑戰性。相反,我們可以嘗試接近。我們可以創建一個索引
TaskSchedulerID
(我們總是過濾那個!),DateLastUpdated
(我們總是排序!),和ItemStatus
(我們過濾那個,但是在 OR 中,所以 SQL 搜尋它有點棘手):CREATE INDEX ix_TaskSchedulerId_ItemStatus ON dbo.TaskSchedulerItem(TaskSchedulerID, DateLastUpdated, ItemStatus);
噓!它在尋找!
這應該使查詢非常快……但是那個小警告符號是什麼?
這就是我所說的“接近”部分。在我的隨機抽樣中,索引搜尋能夠搜尋到 280 行,然後執行一些剩餘 I/O 來找到它需要的符合標準的一行。根據我創建的索引,它將尋找提供的
@TaskSchedulerID
,然後開始沿著DateLastUpdated
列執行(請記住,這是ORDER BY
查詢中的 ,然後執行“剩餘 I/O”以找出該ItemStatus
條件。根據您的數據,這可能足以解決您的性能問題。或者你可能需要更聰明一點。由於我不知道您的實際架構、索引或數據分佈,因此我無法做出更好的猜測。
但實際上,您只需要一個可以使您的查詢執行得更快的索引,這樣您就可以使用更少的 DTU。
您提到它是一個隊列表,因此數據分佈可能是傾斜的:大多數行具有表示完成的狀態,理想情況下只有少數行將成為處理的候選者。對於圖像中的查詢,謂詞中使用的 ItemStatus 值是文字,因此這是過濾索引的完美案例:
CREATE INDEX index_name ON dbo.TaskSchedulerItem(TaskSchedulerID) INCLUDE(DateLastUpdated, ItemStatus, TaskSchedulerItemId) WHERE ItemStatus IN ('PENDING','FAILED', 'IN PROGRESS');
此外,定期清除表會有所幫助:如果它確實是一個隊列,則無需保留已處理的行。