where 子句中的函数调用
Posted
技术标签:
【中文标题】where 子句中的函数调用【英文标题】:Function call in where clause 【发布时间】:2009-11-12 18:23:18 【问题描述】:我有一个查询如下:
SELECT * FROM Members (NOLOCK)
WHERE Phone= dbo.FormatPhone(@Phone)
现在我明白必须对列上的变量应用格式设置。但是我应该将它应用于变量以分配给其他一些局部变量然后使用它(如下所示)。
Set @SomeVar = dbo.FormatPhone(@Phone)
SELECT *
FROM Members (NOLOCK) WHERE Phone= @SomeVar
哪种方式更好或两者都好?
编辑:第一个查询与
有何不同SELECT * FROM Members (NOLOCK)
WHERE dbo.FormatPhone(Phone) = @Phone
【问题讨论】:
【参考方案1】:与 SQL 一样,在不知道实际使用的架构的情况下,查询在很大程度上是不相关的。
您有关于 Members.Phone 的索引吗?如果不是,那么编写查询的方式没有任何区别,它们都会扫描整个表并执行相同的操作(即执行很差)。如果您确实有一个索引,那么您编写查询的方式就完全不同了:
SELECT * FROM Members WHERE Phone= @Phone;
SELECT * FROM Members WHERE Phone= dbo.FormatPhone(@Phone);
SELECT * FROM Members WHERE dbo.FormatPhone(Phone)=@Phone;
保证第一个查询是最优的,将在索引上寻找电话。 第二个查询取决于 dbo.FormatPhone 的特性。它可能会或可能不会使用最佳搜索。 最后一个查询肯定是坏的。将扫描表。
另外,我删除了 NOLOCK 提示,这似乎是当天的主题......见syntax for nolock in sql。 NOLOCK总是是错误的答案。使用快照隔离。
【讨论】:
我浏览了这篇文章,它谈到了不要将 NOLOCK 与 Update/Insert 语句一起使用。我不明白为什么这里有问题? 你的意思是使用 with(nolock) 而不是 NOLOCK? 您是否打算读取未提交的数据?或者您是否添加了 NOLOCK 作为并发问题的解决方法? 在这种情况下并发不是问题,只要我能迅速完成工作。【参考方案2】:如果您首先分配给一个变量,您几乎肯定会获得更好的可预测性,优化器中围绕确定性与非确定性的大量依赖关系。
【讨论】:
【参考方案3】:第二个绝对是首选。 第一个将计算表中每一行的函数,而另一个将只计算一次。
【讨论】:
此外,第一个选项很可能无法使用索引。 如果我们对表列或变量应用函数,每一行的函数评估都会在那里?还是两种方式都一样? 不,如果您预先执行计算,您实际上是在将查询交给一个常量。 你的意思是这两个查询是一样的? SELECT * FROM Members (NOLOCK) WHERE Phone= dbo.FormatPhone(@Phone) SELECT * FROM Members (NOLOCK) WHERE dbo.FormatPhone(Phone) = @Phone 不,这两个查询不一样。执行“WHERE Phone = dbo.FormatPhone(@Phone)”和“WHERE Phone = @FormattedPhone”应该是一样的。【参考方案4】:SELECT * FROM Members (NOLOCK)
WHERE Phone= dbo.FormatPhone(@Phone)
在上面的查询中,function dbo.FormatPhone
将针对Members
表中的每一行执行。
当第二次查询时
Set @SomeVar = dbo.FormatPhone(@Phone)
SELECT *
FROM Members (NOLOCK) WHERE Phone= @SomeVar
它只会执行一次函数。因此,如果成员表中有大量数据,我认为第二种选择会更快。
【讨论】:
谢谢vrunda。我在这里得到了不同的回应和意见,尽管我不相信该函数会在第一个查询中为每一行执行。您有任何参考资料可以证明这一点吗?以上是关于where 子句中的函数调用的主要内容,如果未能解决你的问题,请参考以下文章
如何在 IQueryable 的 where 子句中调用函数
为啥在 CTE 中的 WHERE 子句之前执行 UDF 调用?