CROSS APPLY具有表值函数限制性能

时间:2013-04-26 11:51:26

标签: sql-server performance restriction cross-apply

我对CROSS APPLY有参数化表值函数的问题。 这是简化的伪代码示例:

SELECT * 
FROM (
    SELECT lor.*
    FROM LOT_OF_ROWS_TABLE lor
    WHERE ...
) AS lor
CROSS APPLY dbo.HeavyTableValuedFunction(lor.ID) AS htvf
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID 
WHERE ...
  • LOT_OF_ROWS_TABLE上的内部选择返回许多行。
  • 加入表LOT_OF_ROWS_TABLEANOTHER_TABLE只返回一行或几行。
  • 表值函数非常耗时且需要大量时间 选择的行持续很长时间。

我的问题:

对于从LOT_OF_ROWS_TABLE返回的所有行,都会调用该函数,而不管在加入ANOTHER_TABLE时数据是否会受到限制。

选择必须采用所示格式 - 它是生成的,实际上它更加困难。

当我尝试重写它时,它可以非常快,但它不能像这样重写:

SELECT * 
FROM (
    SELECT lor.*
    FROM LOT_OF_ROWS_TABLE lor
    WHERE ...
) AS lor
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID 
CROSS APPLY dbo.HeavyTableValuedFunction(at.ID) AS htvf
WHERE ...

我想知道:

是否有任何设置或提示或强制选择仅为最终受限制的行调用函数的东西?

谢谢。

修改

表值函数非常复杂:http://pastebin.com/w6azRvxR。 我们所讨论的选择是“用户配置”并生成:http://pastebin.com/bFbanY2n

3 个答案:

答案 0 :(得分:2)

您可以使用表变量或临时表

将此查询分为两部分
SELECT lor.*,at.* into #tempresult
FROM (
    SELECT lor.*
    FROM LOT_OF_ROWS_TABLE lor
    WHERE ...
) lor
INNER JOIN ANOTHER_TABLE AS at ON lor.ID = at.ID 
WHERE ...

现在做表值函数的耗时部分

SELECT  * FROM #tempresult
CROSS APPLY dbo.HeavyTableValuedFunction(#tempresult.ID) AS htvf

答案 1 :(得分:1)

我相信这就是你要找的东西。

Plan Forcing Scenario: Create a Plan Guide to Force a Plan Obtained from a Rewritten Query

基本上它描述了重写查询以使用正确的连接顺序获取生成的计划。然后保存该计划并强制您现有的查询(不会更改)使用您保存的计划。

我放入的BOL链接甚至给出了一个特定的例子,即重新编写查询,以不同的顺序放置连接并使用FORCE ORDER提示。然后使用sp_create_plan_guild从重写的查询中获取计划,并将其用于原始查询。

答案 2 :(得分:0)

是和否......如果没有样本数据IN和结果OUT,很难在你想要实现的目标之间进行比较,以比较结果。

  

我想知道:

     

是否存在强制选择呼叫的设置或提示或其他内容   函数仅适用于最终受限制的行?

所以我会直接回答你上面的问题(3年后!!),直接声明:

  

您需要了解CTE和CROSS APPLY之间的区别   与INNER JOIN相比,为什么在你的情况下使用CROSS APPLY   必要。您“可以”在您的函数中获取代码并应用它   使用CTE将SQL语句转换为单个SQL语句。

即:

阅读thisthis

基本上,这样的事情......

WITH    t2o AS
        (
        SELECT  t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
        FROM    t2
        )
SELECT  t1.*, t2o.*
FROM    t1
INNER JOIN
        t2o
ON      t2o.t1_id = t1.id
        AND t2o.rn <= 3

应用您的查询来推断您想要ONCE的日期,并使用CTE,然后使用CROSS APPLY应用您的第二个SQL。

你别无选择。你不能在一个SQL中做你想做的事。