2015-06-09 19 views
5

我正在探索提高應用程序性能的方法,我只能在有限的程度上影響數據庫級別。 SQL Server版本是2012 SP2,問題中的表和視圖結構是(我真的不能影響此+注意,XML文檔可能總共有幾百個元素):Sql Server:選擇性XML索引不被有效使用

CREATE TABLE Orders(
    id nvarchar(64) NOT NULL, 
    xmldoc xml NULL, 
    CONSTRAINT PK_Order_id PRIMARY KEY CLUSTERED (id) 
); 

CREATE VIEW V_Orders as 
SELECT 
    a.id, a.xmldoc 
    ,a.xmldoc.value('data(/row/c1)[1]', 'nvarchar(max)') "Stuff" 
    ,a.xmldoc.value('data(/row/c2)[1]', 'nvarchar(max)') "OrderType" 
etc..... many columns 
from Orders a; 

一個典型的查詢(和一個被用於以下測試):

SELECT id FROM V_Orders WHERE OrderType = '30791' 

所有查詢都通過視圖進行,我可以既不影響查詢也不表/視圖結構。

我想添加一個選擇性XML索引表將是我的救星:

CREATE SELECTIVE XML INDEX I_Orders_OrderType ON Orders(xmldoc) 
FOR(
    pathOrderType = '/row/c2' as SQL [nvarchar](20) 
) 

但即使更新後統計的執行計劃正在怪異。無法將照片作爲新帳戶發佈,因此相關詳細信息爲文本:

  • 聚合索引seek from selectiveXml(成本:總數的2%)。預期數目的行1,但執行時間預期數1269
  • (表中的行的數量) - >前N排序(成本:95的總%)
  • - >計算標量(成本0)

  • 獨立分支:聚集索引掃描PK_Order_id(成本:總數的3%)。預計行數1269

  • - >合併與嵌套循環計算機標結果(LEFT OUTER JOIN)
  • - >過濾
  • - >最終結果(預計1269行數)

實際上,對於我的測試數據,查詢甚至不會返回任何結果,但它是否返回一個或幾個沒有任何區別。執行時間支持查詢,只要可以從執行計劃中推導出來並具有數千的讀取計數。

所以我的問題是爲什麼選擇性XML索引沒有被優化器正確使用?或者我有什麼問題?我如何使用選擇性xml索引(或者可能持久化的列)來優化這個特定查詢的性能?

編輯: 我對更大的樣本數據進行了額外的測試(表中〜274k行,XML文檔接近平均生產大小),並將選擇性XML索引與升級列進行比較。結果來自Profiler trace,主要集中在CPU使用率和讀取次數上。選擇性xml索引的執行計劃與上述內容基本相同。

選擇性XML索引和274K行(執行上面的查詢): CPU:6454,上寫着:938521

我在搜索領域更新的值後,是唯一的(總記錄還是274K)我得到了結果如下:

選擇性XML索引和274K行(執行上述查詢): CPU:10077,讀取:1006466

然後,使用促進的(即持久)分別索引列,並直接在該視圖使用它: CPU:0,讀取:23

選擇性XML索引性能似乎比正確的SQL索引列提取更接近全表掃描。我在某處讀到使用表的模式可能會幫助從執行計劃中刪除TOP N步驟(假設我們正在尋找一個非重複字段),但我不確定這種情況下是否可行。

+0

您可以將圖片上傳到其他圖片託管網站並在此處發佈鏈接。如果有足夠聲譽的人認爲這個問題很有價值,那麼他們會很樂意幫助你將這個圖像包含在你的文章中。 – har07

+0

感謝您的提示。我不認爲這張照片真的會增加很多,因爲我已經用文字輸入了細節。 – Consulmagician

+1

有關此問題的更多信息,請參見[數據庫管理員的問題與答案](http://dba.stackexchange.com/questions/103867/why-is-the-secondary-selective-index-not-used-when-the-where -clause-filters-on) –

回答

4

創建的選擇性XML索引存儲在內部表中,其主鍵爲Orders,作爲內部表的聚集鍵的主要列,並且指定的路徑存儲爲稀疏列。

你可能查詢計劃看起來是這樣的:

enter image description here

你有一個掃描整個Orders表內表尋求在訂單每一行的主鍵。最終的Filter運算符負責檢查僅返回匹配行的OrderType的值。

不是真的,你所期望的東西叫做索引。

爲了拯救出現了一個次要的選擇性XML索引。它們是爲主要選擇性索引中指定的路徑之一創建的,並將在路徑表達式中提取的值上創建非聚集鍵。然而,並不是那麼容易。 SQL Server不會在values()函數提取的值上使用的謂詞上使用二級索引。您必須改用exists()。此外,exists()要求在路徑表達式中使用XQUERY數據類型,其中value()使用SQL數據類型。

您的主要選擇XML索引看起來是這樣的:

CREATE SELECTIVE XML INDEX I_Orders_OrderType ON Orders(xmldoc) 
FOR 
(
    pathOrderType = '/row/c2' as sql nvarchar(20), 
    pathOrderTypeX = '/row/c2/text()' as xquery 'xs:string' maxlength (20) 
) 

有二次上pathOrderTypeX

CREATE XML INDEX I_Orders_OrderType2 ON Orders(xmldoc) 
    USING XML INDEX I_Orders_OrderType FOR (pathOrderTypeX) 

而對於使用exist()的查詢,您將得到此計劃。

select id 
from V_Orders 
where xmldoc.exist('/row/c2/text()[. = "30791"]') = 1 

enter image description here

首先追求的是尋找你在內部表中的非聚集索引查找的值。密鑰查找是在內部表的聚簇密鑰上完成的(不知道爲什麼這是必要的)。最後的查找是在Orders表中的主鍵上,後跟一個過濾器,用於檢查xmldoc列中的空值。

如果你可以脫身使用property promotion,在XML中的Orders表中創建計算索引列,我想你仍然可以獲得比使用輔助選擇性XML索引更好的性能。

+0

優秀的答案!謝謝。這幫助我瞭解選擇性xml索引如何在隱藏和限制條件下工作。不幸的是,這也意味着我實際上不能在目前的情況下使用它,但希望這可以在別處和其他地方使用。選擇性索引似乎不適用於我的確切問題的原因是,正在使用.exist的情況下,xpath查詢的一部分在視圖中,因此它是實際查詢和查看查詢的組合,並且這會導致很好的執行計劃被切碎。 – Consulmagician

+0

不用擔心。我知道你需要將視圖暴露給某些不想/可以處理'exists()'中的xpath表達式的用戶。一旦我通過構建一個表值UDF來解決這個問題,在這種情況下,將使用orderid作爲參數,在具有'sql:column()'的'exists()'查詢中使用它,並返回所有匹配的id。然後視圖的用戶只需要將UDF加入到視圖中,並將該UDDE作爲參數提供給UDF。或者UDF可以在where子句中用作id in(從UDF(123456)選擇id)''。 –