【问题标题】:Scalar value function usage in the where clause causing performance issuewhere 子句中的标量值函数使用导致性能问题
【发布时间】:2021-05-02 08:56:25
【问题描述】:

我有一个在 where 子句中使用标量值函数的 sql 查询。

SELECT TOP 1 *
FROM TableName T
WHERE T.SomeID = fn_ScalarValueFunction(100)
ORDER BY T.SomeDate 

执行查询大约需要 1 分钟。但是,如果我单独运行以下查询,它们会在一秒钟内运行。

SELECT fn_ScalarValueFunction(100) = 123

SELECT TOP 1 *
FROM TableName T
WHERE T.SomeID = 123
ORDER BY T.SomeDate 

我检查了执行计划,它对两个查询进行了全表扫描。

如何提高慢查询的性能?

【问题讨论】:

  • 如果您不在 SQL Server 2019(+) 中,则该函数无法从内联中受益。因此,使用内联表值函数可能会更好。
  • 多行标量函数可以慢(我们这里没有定义,所以不可能知道)。转换为 内联 表值函数可以(可能)带来性能优势。
  • where子句中使用标量值函数的问题已经讨论过很多次了。稍微搜索一下 - 但这是一个众所周知的性能问题。也许你应该问自己的第一个问题是你的函数是否真的有用并且真的需要。许多缺乏经验的编码人员过于喜欢将 tsql 模块化,这会导致这样的问题。
  • 事实上,如果 SQL Server 针对表中的 每一 行运行该函数,然后进行排序,我不会感到惊讶;因此为什么它这么慢。
  • 那个实例是 2019 年吗?

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


【解决方案1】:

将函数调用移至FROM 子句:

SELECT TOP 1 T.*
FROM TableName T CROSS JOIN
     (VALUES (fn_ScalarValueFunction(100)) v(val)
WHERE T.SomeID = v.val
ORDER BY T.SomeDate;

在您的版本中,需要为表中的所有行调用标量函数——这会增加开销。如果有可用的索引,此版本实际上可能能够使用SomeId 上的索引。

【讨论】:

  • 感谢您的快速回复。我试过了,但仍然需要 1 分钟才能执行。 SomeId 上没有索引,这可能是问题吗?
  • 我在 SomeId 上创建了一个非聚集索引,但没有运气。
  • @developer 。 . .这很奇怪。表有多大,有多少行符合where 条件?
  • @developer 您正在撤回所有列,因此可能决定不使用索引。 select * 通常很糟糕。索引中有include 列吗?
  • @Gordon Linoff - 表有 10,000 行,其中 11 行符合 where 条件。
【解决方案2】:

你也可以声明一个变量来保存值:

DECLARE @ID int = fn_ScalarValueFunction(100)

SELECT TOP 1 * 
FROM TableName T 
WHERE T.SomeID = @ID 
ORDER BY T.SomeDate 

【讨论】:

  • 感谢您的快速回复。该查询是更大的 SQL 查询的一部分,因此我无法获取变量中的数据。否则,它会解决问题。
【解决方案3】:

您可以尝试使用带有子查询的内连接来仅获得一次标量函数的结果,如下所示

SELECT TOP 1 *
FROM TableName T
inner join
(select fn_ScalarValueFunction(100) as 'scalarID')t1
on t.someID = t1.scalarID
ORDER BY T.SomeDate

【讨论】:

  • @developer 还需要一分钟吗?查询计划已更改?
  • @developer 查询计划必须有所不同
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-10
  • 1970-01-01
相关资源
最近更新 更多