刪除用於所有 PK、FK 和聚集索引的 GUIDS
繼承對具有這種討厭配置的數據庫的控制。它還具有由 NHibernate 生成的大部分程式碼,包括在 GUID 到達數據庫之前生成的 GUID,因此也沒有機會使用 NEWSEQUENTIALID()。
顯然,更改其中一些聽起來像是一項巨大的工作,但更改 Lookups 聽起來並不太痛苦。我已經記錄了從這些建構的碎片和 CL 寬度和 NC 索引,優化器選擇了不正確的計劃等。但是我的任務是解決我有點短的問題。
我目前的計劃是調查可以更改多少,並在此期間向主要索引嚴重的表添加一個標識欄位,並使其成為聚集索引並將 GUID 保留為 PK。這是我能期待的最好的嗎?甚至不值得?我省略的任何其他解決方法?
謝謝
(動議回答)
首先,您必須問自己:為什麼要先追求 GUID(如果有的話)?您最終可能會花費大量時間重新排列表格,而根本沒有任何好處。
我們知道什麼:
- 您聲明查詢是由 NHibernate 生成的。這表明您是一個 OLTP 系統。
- 您的主要等待是 CXPACKET 和 PAGEIOLATCH
- 查詢計劃沒有做你想讓他們做的事情
以上都沒有表明改變 GUID 是最好的做法。原因如下:
首先,雖然遠離 GUID 可能會減少碎片 - 這對您的查詢計劃沒有影響(統計有)。事實上,它甚至可能使事情變得更糟,因為您現在必須處理此處描述的升序關鍵問題:http ://blog.kejser.org/2011/07/01/the-ascending-key-problem -in-fact-tables-part-one-pain/這將導致您的並行查詢執行單執行緒。
其次,CXPACKET 的存在作為高等待表明您正在執行大量並行查詢。這表明您得到錯誤的估計或缺少索引 - GUID 也無濟於事(並且降低 DOP 不是這裡的答案)
第三:即使您確實設法切換到 GUID 並使用您的 20M 行範例,您實際上會節省多少?每行都會大 12B(當然,除非您使用堆,但首先必須很好地理解這一點)。它們有 20M 行 - 這是 240MB 的 RAM(當然,假設頁面已滿,它們只會在鍵上,而不是輔助鍵上)。10 倍是剛剛超過 2GB,而今天花費不到一小時的優質 DBA 諮詢。換句話說:試圖從頁面中擠出更多空間是在浪費金錢和寶貴的時間。
在您的情況下,聽起來您需要從中收集一些數據
sys.dm_exec_query_stats
並嘗試找出性能不佳的真正原因。由於這是 NHibernate,我會注意:
- 參數化不佳的查詢(可以通過簡單的提示或更好的統計數據來修復)
- 過度索引或缺乏良好的覆蓋索引
- 缺乏加盟條件
- 優化器在循環更好時選擇散列連接(您可以暫時使用 OPTION (LOOP JOIN) 來查看是否有可能實現良好的循環連接計劃)
刪除 PAGEIOLATCH 的最佳方法是不要將更多內容擠入記憶體(除非數據庫非常小,或者您可以購買便宜的 RAM)——這是為了避免首先進行糟糕的表掃描。
通過將聚集索引移動到標識並將 GUID 保留為 PK,我在整體性能提升方面取得了巨大成功。
如果您有一個 GUID 作為集群 PK,您是在告訴 SQL 對數據進行物理隨機排序,從而導致主表和非集群索引中的頁面拆分和碎片。
通過讓您的數據庫建立穩固的基礎,您可以查看有問題的查詢並開始挑選。我使用 SQL 分析器並擷取執行時間最長的事務,或者導致最大 I/O 量的事務並從那裡開始。