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 调用?

如何在 SQL where 子句中调用函数/过程?

使用 VBA 函数调用在 QueryEditor 中创建查询以指定 WHERE IN 子句

用于 SELECT 和 WHERE 子句的函数

PostgreSQL 函数不适用于 WHERE 子句