这两个数据库查询在代数上是否相同?
Are these two database queries algebraically identical?
我试图弄清楚这两个查询在逻辑上是否相同 - 从 theoretical/boolean algebra/relational 微积分的角度来看。
我有一个 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
。
- 我不是在寻求问题的解决方案。
我问的是理论问题。
这两个查询的形式通常不具有相同的语义——尽管可能需要更复杂的示例来展示不同的结果。
第一种形式(OR
)有 SELECT ...
但没有 SELECT DISTINCT ...
。所以它might produce duplicate rows。 (请参阅 link 处的参考文献 5、6。)
第二种形式有 ... UNION ...
但没有 ... UNION ALL ...
。所以它 must not produce duplicate rows,即使个人 SELECT ...
不是 DISTINCT
。
OTOH 如果那是具有特定配置的特定 DBMS 上的特定模式的唯一区别,我希望 UNION
(而不是 ALL
)形式表现更差,因为它需要去重。
假设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
子句无需跨行即可删除这些重复项。
我试图弄清楚这两个查询在逻辑上是否相同 - 从 theoretical/boolean algebra/relational 微积分的角度来看。
我有一个 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
。 - 我不是在寻求问题的解决方案。
我问的是理论问题。
这两个查询的形式通常不具有相同的语义——尽管可能需要更复杂的示例来展示不同的结果。
第一种形式(OR
)有 SELECT ...
但没有 SELECT DISTINCT ...
。所以它might produce duplicate rows。 (请参阅 link 处的参考文献 5、6。)
第二种形式有 ... UNION ...
但没有 ... UNION ALL ...
。所以它 must not produce duplicate rows,即使个人 SELECT ...
不是 DISTINCT
。
OTOH 如果那是具有特定配置的特定 DBMS 上的特定模式的唯一区别,我希望 UNION
(而不是 ALL
)形式表现更差,因为它需要去重。
假设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
子句无需跨行即可删除这些重复项。