避免WHERE子句中的重复函数调用

时间:2013-10-25 14:31:35

标签: sql tsql function

我知道这很糟糕,我只是不知道如何重新编写它...任何帮助表示赞赏!

DECLARE @i   INT, 
    @var VARCHAR(max) 

SET @i = 0 

WHILE 1 = 1 
BEGIN 
  INSERT INTO mrs.dbo.nav_worldcheck_results 
              ("counter", 
               "entity no", 
               "entity first name", 
               "entity last name", 
               "entity full name", 
               "worldcheck uid", 
               "worldcheck first name", 
               "worldcheck last name", 
               "worldcheck full name", 
               "percentage match") 
  SELECT TOP(1) [Counter] = @i, 
                EN.[entity no_], 
                EN.[name 2], 
                EN.[name], 
                EN.[name 2] + ' ' + EN.[name]          AS EntityName, 
                SM.uid                                 AS WorldCheckID, 
                SM.[first name], 
                SM.[last name], 
                SM.[first name] + ' ' + SM.[last name] AS WorldCheckName, 
                dbo.Fn_calculatejarowinkler(EN.[name 2] + ' ' + EN.[name], 
                SM.[first name] + ' ' + SM.[last name]) 
  FROM   [NAV_LIVE].dbo.[entitytable$entity] AS EN 
         CROSS JOIN [NAV_LIVE].dbo.[worldcheck master] AS SM 
  WHERE  ( EN.inactive = 0 ) 
         AND dbo.Fn_calculatejarowinkler(EN.[name 2] + ' ' + EN.[name], 
                 SM.[first name] + ' ' + SM.[last name]) >= .75 
         AND NOT EXISTS(SELECT * 
                        FROM   mrs.dbo.nav_worldcheck_results AS WCR 
                        WHERE  EN.[entity no_] = WCR.[entity no] 
                               AND WCR.[worldcheck uid] = SM.uid) 

  SET @i = @i + 1 
END 

我想避免在where语句中重复的函数调用,并且我已经尝试将所有作为变量分配然后处理但是我陷入了陷阱,你不能将数据检索与我的可怜的小脑组合在一起星期五模式! :O /

3 个答案:

答案 0 :(得分:0)

看起来你可以优化你的函数调用。如果查询需要定期运行且数据没有变化,您可以考虑预先计算此值。

我建议您阅读更多关于连接的内容,并确定在您的情况下是否真的需要交叉笛卡尔(大多数情况下您实际上需要内连接)。 http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

您还应该咨询您的DBA,以确保您在Indexed列上运行,或者看看他们是否可以添加索引以加快速度。

我还会研究一下你的数据库(我假设是MSSQL)查询调优功能。值得注意的是,解释计划可以更深入地告诉您查询实际在做什么以及您可以在哪里进行优化。

虽然不可能事先知道查询是如何被优化的,但一般来说NOT EXISTS和EXISTS过滤器的效率非常低。特别是如果不存在查询的过滤器返回多行或者它在非索引列上操作。无论哪种方式,我都建议select 1而不是select *,因为减少所选columsn的数量是一种简单的优化。

答案 1 :(得分:0)

在这种情况下,SqlServer查询处理器(看起来像你使用的是SqlServer?)并不一定会为每个返回的行调用dbo.Fn_calculatejarowinkler函数两次(第一次在select子句中,第二次在where子句中),你可能认为。如果函数是确定性的,可能它不会这样做。

您可以重写您的陈述:

SELECT
    ...
    dbo.Fn_calculatejarowinkler(EN.[name 2] + ' ' + EN.[name], 
            SM.[first name] + ' ' + SM.[last name])
    ...
FROM ... AS EN
    CROSS JOIN ... AS SM
WHERE
    ...
    AND dbo.Fn_calculatejarowinkler(EN.[name 2] + ' ' + EN.[name], 
                 SM.[first name] + ' ' + SM.[last name]) >= .75
    ...

以下列方式:

SELECT
    ...
    F.Value,
    ...
FROM ... AS EN
    CROSS JOIN ... AS SM
    CROSS APPLY (
        select dbo.Fn_calculatejarowinkler(EN.[name 2] + ' ' + EN.[name], 
            SM.[first name] + ' ' + SM.[last name])
    ) F(Value)
WHERE
    ...
    AND F.Value >= .75
    ...

但不太可能获得性能。

答案 2 :(得分:0)

感谢大家的期待和花时间回复。

我实际上已经完成了Deadron建议,并使用soundex作为关系而不是交叉连接使用内部联接的混合。

我还添加了使用"差异"进入where子句而不是我的Jaro功能,性能得到了显着改善,并且它的返回命中率足以让人担心。

再次感谢!