2017-07-07 63 views
1

我有它運行在一個OLE-DB查詢鏈接服務器內嵌表值函數,定義適用如下:如何防止交叉的不良優化與內聯表值函數

CREATE FUNCTION [dbo].[fnGetResultsForTag] 
( 
    @elapsedTimeTag NVARCHAR(50) 
) 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT tag, time, value 
    FROM PI.piarchive..picount 
    WHERE tag = @elapsedTimeTag 
     AND filterexpr = QUOTENAME(@elapsedTimeTag, '''') + ' > NEXTVAL(' + QUOTENAME(@elapsedTimeTag, '''') + ', ''*'')' 
     AND time BETWEEN (SELECT result FROM PI.pifunction..date WHERE arg1='t-20h') AND (SELECT result FROM PI.pifunction..date WHERE arg1='*') 
     AND timestep = (SELECT result FROM PI.pifunction..time WHERE arg1='12h') 
     AND calcbasis = 'EventWeighted' 
) 
GO 

這就是所謂的從這樣的存儲過程:

SELECT results.* 
FROM PI.pipoint..pipoint2 points 
CROSS APPLY dbo.fnGetResultsForTag(points.tag) AS results 
WHERE points.tag LIKE @TagPattern 
ORDER BY time ASC, tag ASC 

MS documentation說:

的應用運算符的工作我n個以下方式產生用於FROM子句表源:針對left_table_source以產生行集的每一行

  1. 評估板right_table_source。

    right_table_source中的值取決於left_table_source。 right_table_source可以用這種方式表示:TVF(left_table_source.row),其中TVF是一個表值函數。

  2. 通過執行UNION ALL操作,將right_table_source評估中每行生成的結果集與left_table_source組合在一起。

    APPLY運算符的結果生成的列列表是來自left_table_source的列的集合,與來自right_table_source的列列表組合在一起。

這正是我想要的行爲。但這不是SQL Server實際做的。

實際上會發生什麼情況是,SQL Server查詢優化器試圖通過在WHERE子句中運行的遠程服務器上一個SELECT FROM PI.piarchive..picount查詢,沒有tag = @elapsedTimeTagfilterexpr = <stuff>表達式來優化TVF子查詢,然後做一個在SQL Server中加入以僅選擇指定標籤的數據。

不幸的是,這是不正確的優化。 picount表是包含數千個標籤的底層數據庫視圖。如果tag = @elapsedTimeTag篩選條件未提供給遠程服務器,則查詢超時。並且filterexpr=<stuff>條件需要與標記條件匹配相同的標記名,以獲得正確的答案。所以我真的需要爲左邊表中的每一行運行一個TVF遠程子查詢。

如何提示/強制SQL Server到實際上對CROSS APPLY的左側表格中的每一行運行表值函數的查詢一次,而不是當前正在執行的操作?

我試圖重構外部查詢首先明確選擇標籤列表,但它似乎並沒有幫助:

DECLARE @TagNames AS TABLE (tag NVARCHAR(50) NOT NULL) 

INSERT INTO @TagNames 
SELECT tag FROM PI.pipoint..pipoint2 WHERE tag LIKE @TagPattern 

SELECT results.* 
FROM @TagNames t 
CROSS APPLY dbo.fnGetResultsForTag(t.tag) AS results 
ORDER BY time ASC, tag ASC 
+0

你能發佈執行計劃嗎?您鏈接的文檔可能不適用於ITVF,因爲優化器可以「內聯」該函數 - 它可以內聯函數的主體並運行您的查詢,就像它是一個大選。這可能就是你所看到的這是因爲你的服務器上有一個查詢鏈接服務器數據的ITVF會更加複雜。當您直接在外部服務器實例上運行時,此查詢的行爲如何? –

+0

你希望看到執行計劃的格式是什麼? – Hydrargyrum

+0

如果我直接在外部服務器上運行TVF查詢,提供一個標籤名稱作爲參數,它就像我期望的那樣工作。我認爲外部服務器沒有實現CROSS APPLY,所以外部查詢不能直接運行。這部分必須在SQL Server中。 – Hydrargyrum

回答

1

重寫dbo.fnGetResultsForTag爲多語句表值函數(MTVF),而不是內聯表值函數(ITVF)似乎具有禁止此「優化」的預期效果。

但是,它依賴於實現細節感覺很笨拙,所以我仍然對替代解決方案感興趣,這些解決方案明確指示查詢優化器不要「扁平化」ITVF子查詢。

+0

這就是我最終做的。 – peterdn