2015-10-04 50 views
-2

如果我這樣做,CTE與選項重新編譯後沒有工作

declare @Q varchar(10) = 'ab1'; 
SELECT * 
FROM MyTable 
WHERE EXISTS(SELECT TOP 1 't' InnerTable O WHERE O.TId = P.Id) 
AND (P.Name_EngLIKE @Per_Name + '%' OR P.PER_NAME_ARB LIKE @Per_Name +'%') 

然後查詢變得非常緩慢。如果我評論EXISTS(SELECT TOP 1 't' InnerTable O WHERE O.TId = P.Id)那麼它會很快,或者如果我添加OPTION(RECOMPILE)那麼它會很快。問題是,我使用CTE這個SQL(公用表表達式)不容許我把OPTION(RECOMPILE)

編輯: 這裏是我的CTE,

WITH CTEPage AS 
(
    SELECT Top(@PageSize * @PageIndex) 
      ROW_NUMBER() OVER (ORDER BY P.Id) AS RowNumber 
    FROM MyTable(NOLOCK) AS P 
    WHERE EXISTS(SELECT TOP 1 't' FROM OtherTable O WHERE O.PId = P.Id) 
      AND (@Name IS NULL OR @Name = '' OR P.NAME_ENG LIKE @Name + '%' OR P.NAME_ARB LIKE @Name + '%') 
) 

SELECT TOP(@PageSize) 
     * 
FROM CTEPage AS P 

WHERE P.[RowNumber] > (@PageIndex - 1) * @PageSize 
     ORDER BY P.[RowNumber] ASC; 

更新: CTE工作。問題是@Name是的NVarChar而NAME_ENG和NAME_ARB類型爲VARCHAR

+0

您需要在整個語句結束時重新編譯選項。你剛剛在CTE的最後? –

+0

我想把它放在CTE中。在CTE之後加入SELECT不會影響性能。 – user960567

+2

也許問題不在於重新編譯選項,而在於如何使用CTE。也許是溫度。表將是一個更好的解決方案。沒有像完整的SQL,表和索引結構和查詢計劃這樣的細節,一切都只是猜測。 –

回答

4

根據Query Hints

查詢提示只能在頂級查詢中指定,而不是在 子查詢。

所以你不能在那裏使用它。你必須在最後寫query hint像:

WITH cte AS 
(
    SELECT ... 
    FROM ... 
) 
SELECT ... 
FROM cte 
OPTION(RECOMPILE) 

但正如你說,它並不能幫助。你也可以嘗試改變EXISTSINNER JOIN像:

SELECT * 
FROM MyTable P 
JOIN InnerTable O 
    ON O.TId = P.Id 
WHERE ...; 

更多可能的解決方案應該創建SqlFiddle,所以我們可以重新創建您的問題。

編輯:

如果你使用SQL Server 2012+考慮使用OFFSET FETCH,而不是像定製分頁的解決方案:

Demo

DECLARE @PageSize INT = 5, 
     @Page INT = 2; 

SELECT * 
FROM tab 
ORDER BY id 
OFFSET @PageSize * (@Page - 1) ROWS FETCH NEXT @PageSize ROWS ONLY 
+0

INNER JOIN不會產生任何效果 – user960567

+0

@ user960567請提供http://sqlfiddle.com,否則它幾乎不可能提供幫助。重命名所有表和數據,以便不會有敏感數據。 – lad2025

+0

@ user960567您使用的是哪個版本的SQL Server? – lad2025

1

我不認爲你的問題是「選項重新編譯」,但最有可能的事實是,您的SQL非常複雜,SQL Server無法估計該行正確選擇,或爲所選計劃創建正確的成本估算(或創建計劃超時)。

爲了弄清楚發生了什麼問題,您應該查看實際的執行計劃和統計數據輸出,並查看CTE中代碼的調用次數,是否有算子的估計和實際行數至少偏離10倍或者可能是100x,並且索引是否正確使用。

來自CTE的結果在默認情況下不會被緩存到任何位置,並且該計劃可能會導致代碼被調用數百或數千次,您可以嘗試首先在CTE中運行代碼並將結果存儲到臨時目錄中。該表適當編入索引,以便與其餘數據結合。