Azure-Sql-Database

查詢執行很快,但有時永遠不會完成

  • September 8, 2017

我在工作中搞砸了(哦,不!)。直到大約兩天前,一切都執行良好。查詢立即執行,並且數據庫往往處於 20% 左右的負載。然後我被告知我們在數據庫中的一些歷史數據輸入錯誤,需要從下表中刪除並重新輸入:

CREATE TABLE TrackerStates(
   [Id] [int] IDENTITY(1,1) NOT NULL,
   [TrackerId] [int] NOT NULL,
   [DateRecorded] [datetime] NOT NULL,
   [Latitude] [float] NOT NULL,
   [Longitude] [float] NOT NULL,
   [Altitude] [float] NOT NULL,
   -- Some other fields
   CONSTRAINT [PK_dbo.TrackerStates] PRIMARY KEY NONCLUSTERED  (Id)
)

CREATE CLUSTERED INDEX IX_TrackerId_DateRecorded_Processed ON TrackerStates (TrackerId, DateRecorded, Processed)
CREATE NONCLUSTERED INDEX IX_TrackerId_Processed ON TrackerStates (TrackerId) WHERE (Processed = 0)

CREATE TABLE TrackingPoints(
   [DatabaseId] [int] NOT NULL,
   [TrackerStateId] [int] NOT NULL,
   [RoadId] [int] NOT NULL,
   [Distance] [float] NOT NULL,
   PRIMARY KEY CLUSTERED (DatabaseId, TrackerStateId),
   FOREIGN KEY (DatabaseId) REFERENCES RammDatabases (Id),
   FOREIGN KEY (TrackerStateId) REFERENCES TrackerStates (Id)
)
CREATE NONCLUSTERED INDEX IX_DatabaseId ON TrackingPoints (DatabaseId)
CREATE NONCLUSTERED INDEX IX_TrackerStateId ON TrackingPoints (TrackerStateId)

CREATE TABLE TrackingSegments(
   [DatabaseId] [int] NOT NULL,
   [StartingStateId] [int] NOT NULL,
   [EndingStateId] [int] NOT NULL,
   [EntityId] [nvarchar](max) NULL,
   PRIMARY KEY CLUSTERED (DatabaseId, StartingStateId, EndingStateId),
   FOREIGN KEY (DatabaseId) REFERENCES RammDatabases (Id),
   FOREIGN KEY (StartingStateId) REFERENCES TrackerStates (Id),
   FOREIGN KEY (EndingStateId) REFERENCES TrackerStates (Id),
   FOREIGN KEY (DatabaseId, StartingStateId) REFERENCES TrackingPoints (DatabaseId, TrackerStateId),
   FOREIGN KEY (DatabaseId, EndingStateId) REFERENCES TrackingPoints (DatabaseId, TrackerStateId)
)
CREATE NONCLUSTERED INDEX IX_DatabaseId ON TrackingSegments (DatabaseId)
CREATE NONCLUSTERED INDEX IX_DatabaseId_StartingStateId ON TrackingSegments (DatabaseId, StartingStateId)
CREATE NONCLUSTERED INDEX IX_DatabaseId_EndingStateId ON TrackingSegments (DatabaseId, EndingStateId)

我第一次嘗試刪除數據的時間太長了——它是歷史數據,所以有幾百萬行。失敗後,我四處詢問,有人建議禁用檢查約束,刪除,然後重新啟用這些特定表的約束(我再也不會這樣做了,糟糕的主意)。禁用和刪除執行得相當快,我不得不讓啟用執行一整夜,但它確實成功了。

從那時起,數據庫一直處於 100% CPU 狀態,並且其中一個查詢有時永遠不會完成。每次都是相同的查詢:

SELECT TOP 500 * FROM TrackerStates WHERE TrackerId = @TrackerId AND Processed = 0 ORDER BY DateRecorded

此查詢使用 index IX_TrackerId_DateRecorded_Processed,通常完全不需要時間來執行。但有時,查詢會一直坐在那裡執行,直到超時(30 秒後)。

到目前為止,我已經嘗試過:

  • 將數據庫擴展至 5 倍大小(更少的超時,但仍然 100% 的 CPU 使用率)
  • 重建索引,因為它們碎片化到大約 80%(沒有區別)
  • 將查詢更改為隔離級別READ UNCOMMITTED(沒有區別)

我能做些什麼來解決這個問題?

好像統計不出來了。根據您發布的計劃,它估計它將讀取 64,000 行,但實際上讀取為零。這是一個非常大的差距。我會建議一些事情。首先,使用全面掃描更新統計資訊。任何索引重建都應該解決這個問題,但是由於這種差異,我想知道那裡是否有什麼東西。接下來,確保所有約束都到位(儘管該計劃沒有引用約束,因為它是使用 TOP 操作的直接索引查找)。最後,擷取系統的等待統計資訊,以查看實際導致執行緩慢的原因。您可以使用擴展事件來擷取此查詢的等待指標,因此這是一種更好的方法。此外,一個 64 歲,除非您有數百萬行,否則從查找中進行的 000 行範圍掃描有點過分。但是,這仍然可能是統計數據關閉的一部分。

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