使用函数优化 SQL 查询

Posted

技术标签:

【中文标题】使用函数优化 SQL 查询【英文标题】:Optimizing SQL query using function 【发布时间】:2014-08-14 12:26:52 【问题描述】:

我有一个运行速度非常慢的存储过程。我运行了 SP 并查看了执行计划,并且能够看到花费了这么长时间。

慢的部分:

DECLARE
 @id int 
,@date datetime
,@endDate datetime 


SELECT   @id = 3483
        ,@date = DATEADD(DAY, -10, GETDATE())
        ,@endDate = GETDATE()


SET NOCOUNT ON

SELECT   *
        ,prevId = dbo.fnGetPrevId(id)   
FROM    dbo.table WITH(READUNCOMMITTED)

这个查询中比较慢的部分是我调用函数 dbo.fnGetPrevId 的地方。

dbo.fnGetPrevId:

DECLARE  @prevId int

SELECT  TOP 1 @prevId = t2.id 
FROM    dbo.table2 AS t2 WITH(READUNCOMMITTED)

RETURN @prevId

是否可以在不创建索引或类似的东西的情况下重写以获得更好的性能?

【问题讨论】:

是的,但是我该怎么做呢?做不到 = nPrevResultsId = (SELECT TOP 1...) ? 【参考方案1】:

您可以使用子查询代替标量值函数。

// ...

,prevId = (
 SELECT  TOP 1 x.id
 FROM    dbo.table AS x WITH(READUNCOMMITTED)
 WHERE 1 = 1)

// ...

在大多数情况下,最好避免引用表的标量值函数,因为它们基本上是每行需要运行一次的黑盒,并且无法通过查询计划引擎进行优化。

【讨论】:

会尝试这个解决方案 非常感谢。那效果好多了。怎么这么快? @krillezzz:如前所述,该函数是优化器的黑匣子,引擎可能不使用索引或其他优化。这是一个相关的问题:Why is a UDF so much slower than a subquery?【参考方案2】:

首先,您应该将函数全部剪切并内联查询。从我看来,这将是相当简单的。或者,如果您想保留一个函数,请使用表值函数。对于这两项检查:

http://technet.microsoft.com/en-us/library/ms175156(v=sql.105).aspx

其次,构建索引将获得最佳优化结果(巨大改进)

【讨论】:

索引不是我的选择【参考方案3】:

您的 UDF 正在针对它运行的每一行重新编译。要停止这种情况,请将函数设为表值内联函数,如下所示:

create function dbo.fnFunction:
( list of parameters here)
Returns Table
As
  Return 
   (
    SELECT TOP 1 id
    FROM  dbo.table WITH(READUNCOMMITTED)
    WHERE id= @id
       AND id2= @id2
       ...
   ORDER BY date DESC
  )

这消除了对每一行的重新编译,因为内联表值函数中的 SQL 包含在使用它的查询的 sql 中,并存储在整个查询一次且仅一次的缓存计划中。要使用结果,您需要像对待表格一样对待结果。只需在您的外部查询中加入它,检查此link

【讨论】:

【参考方案4】:

首先在 table(id, id2, id3....) 上创建索引。

这可能会解决您的问题。否则,试试cross apply

FROM    dbo.table1 AS x WITH(READUNCOMMITTED) cross apply
        (SELECT  TOP 1 x2.id
         FROM    dbo.table2 as x2 WITH(READUNCOMMITTED)
          WHERE x.id= x2.id
            AND x.id2= x2.id2
            AND x.id3= x2.id3
         ORDER BY x.Date DESC
        ) x

【讨论】:

以上是关于使用函数优化 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 使用分区函数实现查询优化

SQL UDF 和查询优化 [重复]

带窗口函数的简单SQL查询优化

查询优化(MySql/Sql):将函数移出 where 子句

mysql的优化

mysql的sql语句优化5种方式