【问题标题】:DROP & CREATE FUNCTION improved performanceDROP & CREATE FUNCTION 提高了性能
【发布时间】:2018-08-24 10:15:14
【问题描述】:

我有一个在 WHERE 子句中使用多语句表值函数的查询:

WHERE value IN (SELECT * FROM dbo.Split('SO',','))

函数的返回值是一个包含单个单元格的表格,'SO'

我发现没有该功能的查询要快得多:

WHERE value = 'SO'
WHERE value IN ('SO')
WHERE value IN (SELECT 'SO')

最终我在不更改任何代码的情况下删除并创建了该函数,并且查询运行得更快。以前,它不会在一分钟内完成,现在需要一秒钟。

当我删除并重新创建函数时可能会发生什么变化?

【问题讨论】:

    标签: sql sql-server tsql sql-server-2014


    【解决方案1】:

    SQL Server 在第一次调用存储函数和存储过程时编译查询。优化器做出的决定是基于当时的表统计信息和参数。

    这称为参数嗅探(我不喜欢这个术语,因为决策是基于参数和表统计信息)。

    您的经验表明查询计划不是最理想的——这通常是基于哈希的联接和嵌套循环联接之间的区别。有时,您可以使用索引来解决此问题。

    另一个常见的解决方法是在编程代码中强制重新编译查询(或多个查询)。但是,这会产生重新编译的开销。对于需要一分钟才能运行的查询,这种开销应该很小,但如果查询时间不到一秒,这种开销就更大了。

    【讨论】:

      【解决方案2】:

      我会使用CROSS APPLY 而不是IN 子句:

      SELECT t.*
      FROM table t CROSS APPLY
          (SELECT * FROM dbo.Split('SO',',') 
          ) tt
      WHERE t.value = tt.col;
      

      如果你有一个string 有很大的 no_sos 那么IN 子句会给你带来糟糕的表现。

      【讨论】:

        【解决方案3】:

        尝试使用计数表而不是 UDF

        declare @mytbl table (Value varchar(100))
        insert into @mytbl values('Element01'),('Element04')
        
        DECLARE @Parameter VARCHAR(8000)
            SET @Parameter = ',Element01,'
        
        IF OBJECT_ID('dbo.tally') is not null
        drop table dbo.tally
        
        select TOP (select len(@Parameter)) identity(INT,1,1) AS N INTO TALLY FROM Master.dbo.SysColumns sc1,Master.dbo.SysColumns  c2
        
        select * from @mytbl **where Value in (SELECT sUBSTRING(@Parameter,N+1,CHARINDEX(',',@Parameter,n+1)-n-1)
           FROM dbo.Tally
          WHERE N <= LEN(@Parameter)-1
            AND SUBSTRING(@Parameter,N,1) = ','
          )**
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-17
          • 1970-01-01
          • 2012-05-13
          • 2013-08-01
          • 2015-08-09
          • 2010-11-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多