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

Posted

技术标签:

【中文标题】具有表值函数限制性能的 CROSS APPLY【英文标题】:CROSS APPLY with table valued function restriction performance 【发布时间】:2013-04-20 14:06:14 【问题描述】:

我对带有参数化表值函数的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。

【问题讨论】:

陈述显而易见的可能:如果您可以更改查询文本中连接的顺序。那么您可以使用 FORCE_ORDER 查询提示。代码是如何生成的?你有没有办法改变那方面的行为? 将您的 dbo.HeavyTableValuedFunction(..) 多行表值函数更改为内联表值函数。 @RBarryYoung:过于复杂,无法简单地重写为内联函数 @PavelHodek 啊,这就是导致您的问题的原因,所以如果您不向我们展示,我们也无能为力。 @RBarryYoung:表值函数:pastebin.com/w6azRvxR 和我们所说的选择:pastebin.com/bFbanY2n 【参考方案1】:

您可以将此查询分为两部分,使用表变量或临时表

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

【讨论】:

谢谢,但我不能这样做,因为 'lor' 表和交叉应用必须在一起 - 它们代表复杂生成的查询中的一个单元(可以加入更多单元),然后最后过滤(实际上 another_table 是临时表变量,其中包含一些代表最终限制的记录)。【参考方案2】:

我相信这就是您正在寻找的。

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

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

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

【讨论】:

不幸的是,选择是“用户配置”并生成的,它可以加入更多其他表 - 我无法预测计划。【参考方案3】:

是和否...如果没有样本数据输入和结果输出,很难解释您想要实现的目标,以比较结果。

我想知道:

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

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

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

即:

阅读this 和this。

基本上是这样的......

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。

你别无选择。你不能在 ONE SQL 中做你想做的事情。

【讨论】:

以上是关于具有表值函数限制性能的 CROSS APPLY的主要内容,如果未能解决你的问题,请参考以下文章

CROSS APPLY 和 OUTER APPLY 区别

CROSS APPLY和 OUTER APPLY 区别详解

CROSS APPLY和 OUTER APPLY 区别详解

使用 INCLUDE 索引 OUTER/CROSS APPLY 的 WHERE 子句

为啥 CROSS APPLY 与列和聚合函数需要 Group by

CROSS APPLY 风格与性能