这两个数据库查询在逻辑上是等价的吗?

问题描述 投票:0回答:2

我有一个带有

OR
的查询,运行效果很差(即成本为 138 个单位):

SELECT *
FROM Customers
WHERE (FirstName LIKE 'Ian%') OR (LastName LIKE 'Boyd%')

但是返回相同结果的这个查询运行得更好(即 0.6 个单位):

SELECT *
FROM Customers
WHERE (FirstName LIKE 'Ian%')

UNION

SELECT *
FROM Customers
WHERE (LastName LIKE 'Boyd%')

从我向关系数据库引擎请求什么信息的角度来看,这两个查询在逻辑上是等价或相同的。但如果是这样的话,现代复杂的查询优化器应该理解这一切,并且不会以任何不同的方式运行查询。但事实确实如此;我们知道我们都可以将其归因于古怪的查询优化器。所以也许它们等价。

这两个数据库查询在逻辑上是等价的吗?

CREATE TABLE Customers 
( 
    FirstName varchar(50) NOT NULL,
    LastName varchar(50) NOT NULL
)

CREATE INDEX IX_Customers_FirstName ON Customers (FirstName);
CREATE INDEX IX_Customers_LastNmae  ON Customers (LastName);
sql relational-database
2个回答
2
投票

假设

customers
没有重复行,两者在逻辑上是相同的。这是一个合理的假设。

UNION
版本更快,可能是因为 SQL 引擎可以使用
LIKE
模式的索引——它们不以通配符开头。

更快且几乎等效的版本是:

SELECT *
FROM Customers
WHERE FirstName LIKE 'Ian%'
UNION ALL
SELECT *
FROM Customers
WHERE LastName LIKE 'Boyd%' AND FirstName NOT LIKE 'Ian%';

这里唯一的问题是

FirstName
是否为
NULL
。在这种情况下,逻辑甚至会过滤掉匹配的姓氏。完全等效的需要考虑到这一点:

SELECT *
FROM Customers
WHERE FirstName LIKE 'Ian%'
UNION ALL
SELECT *
FROM Customers
WHERE LastName LIKE 'Boyd%' AND
      (FirstName NOT LIKE 'Ian%' OR FirstName IS NULL);

这些版本应该更快,因为它们使用

UNION ALL
而不是
UNION
。后者会产生删除重复项的开销。但是,
WHERE
子句会删除这些重复项,而无需跨行查看。


1
投票

这两个查询的形式通常不具有相同的语义——尽管可能需要更复杂的示例来演示不同的结果。

第一种形式(带有

OR
)有
SELECT ...
但没有
SELECT DISTINCT ...
。因此它可能会产生重复的行。 (请参阅该链接中的参考文献 5、6。)

第二种形式有

... UNION ...
但没有
... UNION ALL ...
。因此它一定不会产生重复的行,即使各个
SELECT ...
不是
DISTINCT

OTOH,如果这是您的特定 DBMS 上的特定模式及其特定配置的唯一区别,我预计

UNION
(不是
ALL
)形式的性能会更差,因为它需要重复数据删除。

© www.soinside.com 2019 - 2024. All rights reserved.