Sql-Server

開發人員的查詢在自定義數據庫中表現很差

  • December 3, 2020

我們有一個內部開發的 Web 應用程序,其數據庫非常小(約 20MB),使用者數量很少(最多約 20 個),不幸的是,它是高管使用的一個非常高知名度的應用程序。他們發現每週下午晚些時候,當多個使用者同時進行更改時,性能極差——有時需要 5 分鐘才能“保存更新”,有時會完全失敗。

表格設計並不理想,我建議開發人員進行一些更改,這需要一些時間來實現。主表有許多varchar(max)列,它們儲存分隔的使用者列表。數據庫中的所有表在 ID 列上都有一個聚集索引——我建議開發人員改進的另一件事。

此應用程序中的一些“項目”明顯比其他“項目”慢,特別是有一個幾乎總是保存緩慢,但在重度使用期之外,我們通常可以看到查詢執行良好。

我不是開發人員,但對於作為 DBA 的我來說,這個查詢看起來很差/效率低 - 這是應用程序的“保存項目”查詢的典型特徵。它看起來是由某些工具自動生成的——查詢是由應用程序生成的,它為表中的每一列傳遞參數,它根本不使用儲存過程。

UPDATE Actions SET Name = @Name,
Start_Date = @Start_Date,
End_Date = @End_Date,
Status = @Status,
Comments = @Comments,
Comp_Date = @Comp_Date,
Owner = @Owner,
Owner_EmplID = @Owner_EmplId,
Status_Name = @Status_Name
WHERE ID = @ID;

該伺服器是 SQL 2012 Standard,它有 4 個 CPU、18GB RAM(對於我們的環境來說非常典型)——它確實執行其他應用程序數據庫,但在此應用程序的高峰使用時間期間,整體伺服器負載是“正常的”,並且沒有作業/負載在高峰使用時間在其他數據庫中執行。在我們監控峰值使用性能時,我根本沒有發現任何死鎖或鎖定。

我們確實有一個 Tableau 報表連接到同一個數據庫,該數據庫會自動生成其他一些糟糕的報表查詢,整個數據庫在所有表中大約有 25,000 行,Tableau 執行的查詢會生成數百萬行;我懷疑它在某個地方交叉加入,但我的同行都不想關注這個問題的這一方面。

這些更新查詢是否真的遵循良好的開發實踐?您能否提供任何建議來幫助我說服開發人員重新設計其中的一些內容,或者在不涉及他們的情況下我可以做些什麼來提高性能?

動作表的定義:

TABLE [dbo].[Actions](
   [ID] [int] IDENTITY(1,1) NOT NULL,
   [Project_ID] [int] NULL,
   [Name] [varchar](1000) NULL,
   [Owner] [varchar](500) NULL,
   [Owner_Emplid] [varchar](500) NULL,
   [Comments] [varchar](max) NULL,
   [Start_Date] [date] NULL,
   [End_Date] [date] NULL,
   [Comp_Date] [date] NULL,
   [Status] [int] NOT NULL,
   [Status_Name] [varchar](50) NULL

varchar(max)帶有分隔列表的列是一種反模式,特別是如果您將這些列表拆分出來。正確設計的關係表可以提供更好的性能。但是,這可能是您的性能問題的次要問題。

我會在阻塞問題上賭錢。來自微軟:

阻塞是任何基於鎖並發的關係數據庫管理系統(RDBMS)的一個不可避免的特徵。在 SQL Server 上,當一個 SPID 持有特定資源上的鎖而第二個 SPID 嘗試獲取同一資源上的衝突鎖類型時,就會發生阻塞。

當 Tableau 查詢需要很長時間才能完成時,可能會發生阻塞,阻止更新發生,並給人一種緩慢的印象。

Brent Ozar 有一套出色的工具可以幫助理解性能問題。特別是圍繞阻塞,此頁麵包含大量資源。

順便說一句,在我看來,您問題中的更新語句對我來說格式正確。如圖所示,我認為它沒有任何問題。如果您為有問題的查詢和更新語句提供查詢計劃,我將提供更明確的建議。

如果您確實發現阻塞是一個重大問題,您可能需要查看 SQL Server 的多版本並發控制選項,該選項可以在數據庫級別啟用,READ COMMITTED SNAPSHOT。從該文件中:

當 READ_COMMITTED_SNAPSHOT 數據庫選項設置為 ON 時,讀送出隔離使用行版本控制來提供語句級讀一致性。讀操作只需要 SCH-S 表級鎖,不需要頁鎖或行鎖。也就是說,SQL Server 數據庫引擎使用行版本控制為每個語句提供一個事務一致的數據快照,因為它在語句開始時就存在。鎖不用於保護數據不被其他事務更新。使用者定義的函式可以返回在包含 UDF 的語句開始之後送出的數據。

請注意,讀取送出的快照隔離 (RCSI) 並不是乍看之下的靈丹妙藥。像大多數事情一樣,它有積極和消極的影響。按照設計,它會更改數據庫的並發配置文件,這樣您就可以不再依賴鎖定來強制執行 select-then-update 語義,因為 select 將不再阻止其他事務訪問即將更新的行。Kendra Little 有一篇 [很棒的文章 (https://littlekendra.com/2016/02/18/how-to-choose-rcsi-snapshot-isolation-levels/) 談論 RCSI。

該更新可能不是問題。

可能有一些選擇持有讀鎖,它需要一段時間才能獲得更新鎖。

查看使用最多的選擇。例如,應用程序是否保留使選擇處於活動狀態的程序 DataReader?

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