在存储过程 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 Server 2005

存储过程系列之调试存储过程 SQL Server 2005

在SQL Server2005中,下面调用存储过程的语句错误的是:

SQL Server 2005 视图与物化视图与存储过程

SQL Server 2005 使用 GETDATE() 作为参数通过 SSIS 运行存储过程

SQL Server 2005 中的内置数据库角色允许执行存储过程?