【问题标题】:Optimizing a recursive UDF with a temp table使用临时表优化递归 UDF
【发布时间】:2015-10-20 11:16:20
【问题描述】:

我有以下函数循环遍历树结构以查看是否有任何子注释包含属性:

CREATE FUNCTION [dbo].[ufn_FamilyHasCar] ( @PersonId Integer ) RETURNS bit
as
BEGIN
    DECLARE @Out bit = 0
    Declare @Count int
    Select @Count = count(*) from car WHERE owner_id = @PersonId and type = 2
    if @Count = 0
        begin 
            declare @tbl_temp table (personId int)
            Declare @Id int
            insert into @tbl_temp(personId) (select id from person where parent_id = @PersonId) 
            While (Select Count(*) From @tbl_temp) > 0
                Begin
                    Select Top 1 @Id = personId From @tbl_temp
                    set @Out = dbo.ufn_FamilyHasCar(@Id)
                    if @Out = 1
                        break
                    Delete from @tbl_temp Where personId = @Id
                End
        end
    else 
    set @Out = 1
RETURN @Out
END
GO

这似乎是我当前实现的瓶颈,所以我想问是否以及如何提高 udf 的性能?

【问题讨论】:

    标签: sql sql-server recursion user-defined-functions


    【解决方案1】:

    我会用递归 CTE 替换它:

    with pp as (
          select p.id
          from person p
          where p.id = @personid
          union all
          select p.id
          from pp join
               person p
               on pp.parentid = p.id
        )
    select (case when count(*) > 0 then 1 else 0 end)
    from pp join
         car c
         on pp.id = c.owner_id and type = 2;
    

    COUNT(*) 是表达查询的最清晰方式。但是,如果有很多匹配项(比如几十个),那么聚合的额外开销就太大了,您可以使用 exists 代替:

    with pp as ( . . .)
    select (case when exists (select 1 from pp join car cc on pp.id = c.owner_id and type = 2)
                 then 1 else 0
            end);
    

    【讨论】:

    • 然后替换对 UDF 的调用还是应该在 UDF 内?
    • @Bugman 。 . .无论哪种方式。您不需要递归,因此您可以根据代码的外观替换 UDF。
    猜你喜欢
    • 2016-12-05
    • 2017-12-31
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    相关资源
    最近更新 更多