2012-09-13 36 views
2

我有一個非常複雜的查詢,它有時返回的結果非常緩慢。從一開始就很明顯,罪魁禍首是與全文搜索有關的WHERE子句的一部分。所以我將其隔離並進行了測試。這個測試結果發現它什麼時候發生,但我至今未能弄清楚如何修復它。這裏的問題是什麼:SQL Server 2008中的邏輯短路似乎失敗CONTAINS全文謂詞

我需要基於用戶想要做一個,兩個或三個全文索引列進行篩選。因爲它似乎是內部的列列表中包含謂詞不能suplied可變我能想出是退而求其次採用一些標準的布爾邏輯,像這樣:

(((@SearchInName = 0 AND @SearchInShortDescr = 0 AND @SearchInHTMLDescr = 0) OR @SearchExpression = '""') 
OR (@SearchInName = 1 AND @SearchInShortDescr = 0 AND @SearchInHTMLDescr = 0 AND CONTAINS(ProductName, @SearchExpression)) 
OR (@SearchInName = 0 AND @SearchInShortDescr = 1 AND @SearchInHTMLDescr = 0 AND CONTAINS(ProductShortDescr, @SearchExpression)) 
OR (@SearchInName = 0 AND @SearchInShortDescr = 0 AND @SearchInHTMLDescr = 1 AND CONTAINS(ProductDescrHTML, @SearchExpression)) 
OR (@SearchInName = 1 AND @SearchInShortDescr = 1 AND @SearchInHTMLDescr = 0 AND CONTAINS((ProductName, ProductShortDescr), @SearchExpression)) 
OR (@SearchInName = 1 AND @SearchInShortDescr = 0 AND @SearchInHTMLDescr = 1 AND CONTAINS((ProductName, ProductDescrHTML), @SearchExpression)) 
OR (@SearchInName = 0 AND @SearchInShortDescr = 1 AND @SearchInHTMLDescr = 1 AND CONTAINS((ProductShortDescr, ProductDescrHTML), @SearchExpression)) 
OR (@SearchInName = 1 AND @SearchInShortDescr = 1 AND @SearchInHTMLDescr = 1 AND CONTAINS((ProductName, ProductShortDescr, ProductDescrHTML), @SearchExpression)) 

這將是罰款和按預期工作(快),只要實際有效條件與最後的OR部分匹配。所以在上面的例子中,當@SearchInName = 1 AND @SearchInShortDescr = 1 AND @SearchInHTMLDescr = 1時(用戶想要在所有3列中搜索)。其他條件如果放在此代碼塊中,則也會很快返回。但是,只要實際有效條件高於上次,看起來它後面的所有CONTAINS語句也同時運行(不一定包括在結果中,雖然這是正確的),執行時間從1s到6秒或更長,具體取決於有效語句的有效程度,因此有多少其他CONTAINS謂詞遵循。由此得出的明顯結論是,由於某些原因,無論如何,以下布爾語句無法短路並運行CONTAINS謂詞。

據我瞭解,執行順序不是由實際的代碼和SQL優化後的一些短路可能無法按設計全靠它,這似乎是這種情況下的工作一直給予。那裏的建議通常是使用CASE語句來確保順序,但不幸的是,CONTAINS語句在CASE語句中似乎並不滿意。

所以,我想我大概那種知道爲什麼它正在發生(的SQL優化),但不能想出辦法如何真正解決這個問題。誰能幫忙?

+2

有* *無*保證哪些謂詞將被評估,何時,即使使用'CASE'(我曾經認爲'CASE'可以用來強加排序,但事實證明並非如此) –

+1

既然這似乎與搜索有關,您可能想要閱讀Erland Sommarskog出色的[SQL中的動態搜索條件](http://www.sommarskog.se/dyn-search.html) –

+0

好吧,據我測試'CASE'無論如何都不能和CONTAINS一起使用,但是謝謝你的提示。 – Marek

回答

1

Sql服務器將緩存計劃,以便它可以重用。直接的含義是SQL Server創建的計劃必須適用於所有情況,因此必須是通用的。這消除了短路邏輯的任何可能性。

一種解決方案是使用OPTION(RECOMPILE)查詢提示。這將強制SQL Server在每次執行時重新編譯查詢。因爲SQL知道這個計劃永遠不會被重用,所以它將檢查參數的值,應用短路邏輯,選擇過濾的索引,並且制定最好的計劃。

這不是一個可怕的解決方案,因爲全文索引反正產生局部重新編譯(你可以根據傳遞的是函數查詢得到不同的計劃)。

另一種方法是使用動態SQL來構建查詢。通過動態SQL,您將獲得兩全其美的優勢:更好的計劃和計劃重用。

您使用的是哪種技術?在大多數情況下,不,沒關係。如果您的查詢非常頻繁地被調用,例如每天3-4百萬次調用,那麼每秒編譯次數可能成爲瓶頸。如果發生這種情況,動態SQL方法是有利的。