鉴于reddit 上的这个问题,我清理了查询以指出问题在查询中的位置。我首先使用逗号WHERE 1=1
,以便更轻松地修改查询,所以我的查询通常会这样结束:
SELECT
C.CompanyName
,O.ShippedDate
,OD.UnitPrice
,P.ProductName
FROM
Customers as C
INNER JOIN Orders as O ON C.CustomerID = O.CustomerID
INNER JOIN [Order Details] as OD ON O.OrderID = OD.OrderID
INNER JOIN Products as P ON P.ProductID = OD.ProductID
Where 1=1
-- AND O.ShippedDate Between '4/1/2008' And '4/30/2008'
And P.productname = 'TOFU'
Order By C.CompanyName
基本上有人说1=1 一般是懒惰的,不利于性能。
鉴于我不想“过早地优化”——我确实想遵循良好的做法。我之前查看过查询计划,但通常只是为了找出我可以添加(或调整)哪些索引以使我的查询运行得更快。
那么这个问题真的……会Where 1=1
导致坏事发生吗?如果是这样,我怎么知道?
次要编辑:我也一直“假设”这1=1
将被优化,或者最坏的情况可以忽略不计。质疑一个口头禅永远不会有坏处,比如“Goto 是邪恶的”或“过早的优化......”或其他假设的事实。不确定是否1=1 AND
会实际影响查询计划。在子查询中呢?CTE? 手续?
除非需要,否则我不是要优化的人......但如果我正在做一些实际上“坏”的事情,我想尽量减少影响或在适用的情况下进行更改。
SQL 服务器
解析器优化器有一个名为“Constant Folding”的功能,可以消除查询中的重言式表达式。如果您查看执行计划,在谓词中的任何地方都不会看到该表达式出现。这意味着由于这个和其他原因,在编译时无论如何都会执行常量折叠,并且它对查询性能没有影响。
有关更多信息,请参阅基数估计期间的常量折叠和表达式评估。
添加冗余谓词可以在 SQL Server 中有所作为。
在下面的执行计划中,请注意
@1
第一个计划中的与第二个计划中的文字'foo'
。这表明 SQL Server 考虑了对简单参数化的第一个查询以促进执行计划重用 - 但是两个常量的比较可以防止这种情况在第二种情况下发生。
可以在计划缓存 Microsoft 技术论文的附录 A 中找到阻止简单参数化(以前称为自动参数化)的条件列表:
无论如何,简单的参数化通常不是您应该依赖的东西。显式参数化查询要好得多。
在任何现代 RDBMS(包括 Oracle、Microsoft SQL Server 和 PostgreSQL——我确信这些)中,这对性能没有影响。
正如有人指出的那样,这只会影响查询计划阶段。因此,只有当您运行不返回任何数据的简单查询的数千次迭代时,差异才会可见,例如:
对我来说,在 PostgreSQL 9.0 上,这仅在 10000 次迭代中可见:
当您使用数据库参数 cursor_sharing 时,这可能是 Oracle 的“问题”。当设置为“强制”时,它将修改所有 SQL 语句。查询中的所有“常量”都将被绑定变量(如 1 => :SYS_0)替换。
引入此选项是为了应对一些懒惰的开发人员。另一方面,它也会伤害其他懒惰的开发者。但风险并不算太高。从 11g 开始,它具有绑定变量窥视功能。