【问题标题】:Use of function calls in stored procedure sql server 2005?在存储过程 sql server 2005 中使用函数调用?
【发布时间】:2011-09-21 19:25:34
【问题描述】:

在存储过程的where子句中使用函数调用会降低sql server 2005的性能?

SELECT * FROM Member M 
WHERE LOWER(dbo.GetLookupDetailTitle(M.RoleId,'MemberRole')) != 'administrator' 
AND LOWER(dbo.GetLookupDetailTitle(M.RoleId,'MemberRole')) != 'moderator' 

在这个查询中,GetLookupDetailTitle 是一个用户定义的函数,而 LOWER() 是我所询问的内置函数。

【问题讨论】:

  • 信息肯定不够!什么函数调用?我们可以看看 SQL 吗?
  • 将函数应用于 where 子句中的列会否定使用该列上的任何索引的能力。这通常被称为非 sargable 查询。

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


【解决方案1】:

是的。

这两种做法都应尽可能避免。

almost any 函数应用于列会使表达式不可分割,这意味着无法使用索引,即使该列没有被索引,它也会使计划其余部分的基数估计不正确。

此外,您的 dbo.GetLookupDetailTitle 标量函数看起来像是进行数据访问,这应该内联到查询中。

查询优化器不会从标量 UDF 中内联逻辑,您的查询将对源数据中的每一行执行此查找,这将有效地强制执行嵌套循环连接,而不管其适用性如何。

此外,由于 2 次函数调用,这实际上每行会发生 两次。您可能应该重写为类似

SELECT M.* /*But don't use * either, list columns explicitly... */
FROM Member M 
WHERE NOT EXISTS(SELECT * 
                 FROM MemberRoles R 
                 WHERE R.MemberId = M.MemberId 
                 AND R.RoleId IN (1,2)
                 )

不要试图将文字值 1,2 替换为具有更多描述性名称的变量,因为这也会破坏基数估计。

【讨论】:

  • 请参阅this post,了解有关不可分割查询的更多信息以及避免它们的一些策略。
  • ok 如果我在 where 子句中使用 LOWER、UPPER、LTRIM 等函数,会影响性能?
  • @user441052 - 是的,他们会阻止使用索引来查找与谓词匹配的行。如果您想要不区分大小写的比较,请确保将数据存储在不区分大小写排序规则的列中。如果您通常留下的尾随空格会弄乱您的比较,请一次性整理并修复您的查询,以便在insert / update 时间将其删除。
【解决方案2】:

WHERE 子句中使用函数强制进行表扫描。

没有办法使用索引,因为引擎在对表中的每一行运行函数之前无法知道结果是什么。

【讨论】:

【解决方案3】:

你可以同时避免用户定义的函数和内置的by

  • 为管理员和主持人角色定义“神奇”值并将 Member.RoleId 与这些标量进行比较

  • 在 MemberRole 表上定义 IsAdministrator 和 IsModerator 标志,并与 Member 连接以过滤这些标志

【讨论】:

    猜你喜欢
    • 2011-09-14
    • 1970-01-01
    • 2016-11-02
    • 2012-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多