使用 OR 逻辑是因为它符合人们的思维习惯。用使用 OR 逻辑的逻辑表达式来确定优先级和标识锚点行之后的行,也相当直观。
但是,因为 SQL Server 优化器的工作方式,OR 逻辑在性能方面存在问题,特别是当一些被筛选的列上没有索引时。
例如,考虑这样一个筛选器“col1=5 or col2=10”。如果分别在 col1 和 col2 上有单独的索引,优化器可以先在每个索引中筛选出行,然后再对两个结果执行索引交集运算(index intersection)运算。然而,如果只在其中一列上有索引,即使筛选器的选择性非常高,这个索引也没什么用。为了确定不满足第一个筛选条件的行是否满足第二个筛选条件,SQL server 还是需要扫描整个表。
另一方面,AND 逻辑在性能上具有更好的潜力。每个表达式都会缩小结果集的范围。在一个索引上筛选出的行已经是最终要返回的行的超集。所以,被筛选列上的任何索引都可能会有潜在的利用价值。是否值得使用已有的索引,得由选择性来决定,但至少有使用的可能,例如,考虑筛选器“col1=5 and col2=10”。这时最佳索引是在这两个列上创建的组合索引。然后,如果只在其中一列上具有索引,而且选项也足够高,这已经足够了。SQL Server 可以通过这个索引筛选数据,然后查找这些行,检查它们是否也满足第二个条件。
使用下面的逻辑来筛选行:
orderdate>'20080506' or ( orderdate = '20080506' and orderid >11075 )
等价于:
orderdate>='20080506' and ( orderdate > '20080506' and orderid >11075 )
--实验如下:
IF OBJECT_ID('dbo.MyOrders') IS NOT NULL
DROP TABLE dbo.MyOrders;
GO
SELECT * INTO dbo.MyOrders FROM Sales.Orders
CREATE INDEX idx_dt ON dbo.MyOrders(orderdate);
DROP TABLE dbo.MyOrders;
GO
SELECT * INTO dbo.MyOrders FROM Sales.Orders
CREATE INDEX idx_dt ON dbo.MyOrders(orderdate);
使用 or 逻辑运算符:
SELECT orderid, orderdate, custid, empid
FROM dbo.MyOrders
WHERE orderdate > '20080506'
OR (orderdate = '20080506' AND orderid > 11075);
FROM dbo.MyOrders
WHERE orderdate > '20080506'
OR (orderdate = '20080506' AND orderid > 11075);
使用 and 逻辑运算符:
SELECT orderid, orderdate, custid, empid
FROM dbo.MyOrders
WHERE orderdate >= '20080506'
AND (orderdate > '20080506' OR orderid > 11075);
FROM dbo.MyOrders
WHERE orderdate >= '20080506'
AND (orderdate > '20080506' OR orderid > 11075);
创建了组合索引之后,效果更加
CREATE INDEX idx_dt_oid ON dbo.MyOrders(orderdate, orderid);
结论显而易见:
《1》、与 OR 逻辑相比,SQL Server 对 AND 逻辑能进行更好的优化。同样,也能对其他逻辑表达式实现这种转换。
《2》、另一个结论是最好在决定优先级的所有列上创建一个索引。但问题是在产品环境中,并不总是能做到这一点。