为啥在 CTE 中的 WHERE 子句之前执行 UDF 调用?

Posted

技术标签:

【中文标题】为啥在 CTE 中的 WHERE 子句之前执行 UDF 调用?【英文标题】:Why UDF call is being executed before the WHERE clause in a CTE?为什么在 CTE 中的 WHERE 子句之前执行 UDF 调用? 【发布时间】:2018-04-28 17:03:03 【问题描述】:

我试图理解为什么带有 UDF(用户定义函数)调用的 CTE(公用表表达式)如此缓慢。

表 TABLE1 有 1000 万行。 最后一个 where 子句 (ROWN = 1) 过滤并仅返回 10 条记录。

由于未知原因,MYFUNCTION 被调用了数百万次(在 WHERE 子句过滤器之前),它正在减慢查询速度。如果 MYFUNCTION 调用被删除,查询会立即运行。

如何强制 SQL 仅在应用 WHERE 子句后才运行 MYFUNCTION?


WITH MAINDATA
AS
(
    SELECT
        FIELD1,
        FIELD2,
        FIELD3,
        ROW_NUMBER() OVER (PARTITION BY FIELD5 ORDER BY FIELD6) AS ROWN
    FROM
        TABLE1
)
SELECT
    FIELD1,
    dbo.MYFUNCTION(FIELD2, FIELD3) AS FUNCTIONRESULT
FROM
    MAINDATA
WHERE
    ROWN = 1

【问题讨论】:

可能是因为标量 UDF 的成本计算是垃圾(直到发布在 froid 上完成的工作) - 你可以将它重写为内联 TVF 吗? @MartinSmith 我不能,这是一个复杂的功能。转换为 CLR UDF,它的速度惊人地快。只是想了解SQL决定在过滤之前调用该函数的原因。 如果可能,您能否添加 UDF 定义?它可能有助于了解 Froid 是否能够内联 UDF。 【参考方案1】:

您是否尝试添加顺序 cte?

WITH MAINDATA
AS
(
    SELECT
        FIELD1,
        FIELD2,
        FIELD3,
        ROW_NUMBER() OVER (PARTITION BY FIELD5 ORDER BY FIELD6) AS ROWN
    FROM
        TABLE1
) ,
RESULTS (
        SELECT 
            FIELD1
        FROM
            MAINDATA
        WHERE
            ROWN = 1
)
SELECT *
      ,dbo.MYFUNCTION(FIELD2, FIELD3) AS FUNCTIONRESULT
FROM  RESULTS

【讨论】:

以上是关于为啥在 CTE 中的 WHERE 子句之前执行 UDF 调用?的主要内容,如果未能解决你的问题,请参考以下文章

SQL中的WHERE子句中为啥不允许应用聚集函数呢?请通俗的解释一下或者谈谈自己的见解!

为啥在具有多个连接的 WHERE 子句中,子查询比文字值执行得更好?

为啥聚集函数不能出现在where子句中

PSQL 中的 CTE/with 子句

GREENPLUM中的with,即CTE用法,转自gp中文网文档

使用 SSMS 在 where 子句中的每个 id 之前放置逗号