在存储过程 sql server 2005 中使用函数调用?
Posted
技术标签:
【中文标题】在存储过程 sql server 2005 中使用函数调用?【英文标题】:Use of function calls in stored procedure 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 查询。 【参考方案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
子句中使用函数强制进行表扫描。
没有办法使用索引,因为引擎在对表中的每一行运行函数之前无法知道结果是什么。
【讨论】:
LEFT
不是 sargable AFAIK。 It is included in this connect item as one that could be but isn't.
@MartinSmith - 以为是,但不是。更正了帖子。【参考方案3】:
你可以同时避免用户定义的函数和内置的by
为管理员和主持人角色定义“神奇”值并将 Member.RoleId 与这些标量进行比较
在 MemberRole 表上定义 IsAdministrator 和 IsModerator 标志,并与 Member 连接以过滤这些标志
【讨论】:
以上是关于在存储过程 sql server 2005 中使用函数调用?的主要内容,如果未能解决你的问题,请参考以下文章
在SQL Server2005中,下面调用存储过程的语句错误的是: