这两个数据库查询在代数上相同吗?

问题描述 投票: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%')
现在在我看来,这两个查询在逻辑上是等价或相同的——从我向关系数据库引擎询问什么信息的角度来看。但如果是这样的话,现代复杂的查询优化器应该理解这一切,并且不会以任何不同的方式运行查询。但事实确实如此;我们知道我们都可以将其归因于古怪的查询优化器。

当然,除非它们

实际上是等价的。

在这种情况下:我想知道:

查询 A查询 B

注意

这不是一个关于性能调优的问题,涉及DDL、数据量,或者要求任何人来调优查询。如果这就是数据库引擎运行第二个查询的方式:那么我只需要忍受愚蠢的优化器。这是一个与语言无关、与数据库无关的理论问题。

    我不是问如何清除程序缓存,
  • 我不是问如何执行
  • WITH RECOMPILE
  • 我不是在寻求问题的解决方案。
我在问一个理论问题。

CRME

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); SELECT * FROM Customers WHERE (FirstName LIKE 'Ian%') OR (LastName LIKE 'Boyd%')
    
sql relational-database theory relational-algebra
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.