我们在数据库上有两个查询,唯一的区别是OR子句中条件的顺序。

具有相同结构的查询可以在另一个数据库上的相似数据集上正常工作。我们正在使用Oracle 12.2
Bestand表具有两个连接的实体,其中任何一个始终被填充。在我们的示例中,Article已连接,KbArticle始终为null
在我们的一个查询中,我们获得了所有文章id都适用的结果,而在另一种情况下则不然。
所有Bestand实体都满足最后两个条件(cod_lbr = 12, flg_sperre = 0)

SELECT bestand0_.*
FROM tbl_bestand bestand0_
LEFT OUTER JOIN tbl_kb_artikel customeror1_
ON bestand0_.id_kb_artikel=customeror1_.id_kb_artikel
LEFT OUTER JOIN tbl_artikel article2_
ON bestand0_.id_artikel          =article2_.id_artikel
WHERE (customeror1_.id_kb_artikel=3017874 OR article2_.id_artikel          =3017874)
AND bestand0_.cod_lbr            =12
AND NVL(bestand0_.flg_sperre,0)  = 0;

产生结果 Link to Explain Plan
SELECT bestand0_.*
FROM tbl_bestand bestand0_
LEFT OUTER JOIN tbl_kb_artikel customeror1_
ON bestand0_.id_kb_artikel=customeror1_.id_kb_artikel
LEFT OUTER JOIN tbl_artikel article2_
ON bestand0_.id_artikel          =article2_.id_artikel
WHERE (article2_.id_artikel          =3017874 OR customeror1_.id_kb_artikel=3017874)
AND bestand0_.cod_lbr            =12
AND NVL(bestand0_.flg_sperre,0)  = 0;

没有结果 Link to Explain Plan

对我而言,绝对没有任何意义,因为我们应该获取满足where子句中所有语句的所有结果是,如果您保留最后两个条件,则查询将返回预期结果,因此,如果将查询修改为:
SELECT bestand0_.*
FROM tbl_bestand bestand0_
LEFT OUTER JOIN tbl_kb_artikel customeror1_
ON bestand0_.id_kb_artikel=customeror1_.id_kb_artikel
LEFT OUTER JOIN tbl_artikel article2_
ON bestand0_.id_artikel          =article2_.id_artikel
WHERE (article2_.id_artikel          =3017874 OR customeror1_.id_kb_artikel=3017874);

我们再次获得结果 Link to Explain Plan

我希望两个查询都能产生相同的结果,但我不明白为什么条件的顺序应该以任何方式影响查询的结果。
这里有一些索引弄乱了吗?
它必须是特定于数据库的,因为我们的查询可以在另一个具有相同数据集的相同版本的数据库上正常工作。

** 更新 **

不幸的是,使用AND OTHER_ID IS NULL作为@kfinity的查询与上面的查询存在相同的问题,这对我来说绝对没有意义。在禁用@Kuvick提到的查询的自适应统计优化器之后,两个查询均再次返回结果,并带有以下说明计划:

Explain plan Query 1
Explain plan Query 2

因此,关闭该优化程序可以解决我们的问题。

最佳答案

我们将问题确定为Oracle设置OPTIMIZER_ADAPTIVE_PLANS和OPTIMIZER_ADAPTIVE_STATISTICS。设置数据库后,默认情况下,第一个处于事件状态,第二个处于禁用状态。

在我们的情况下,两个都被激活。在停用OPTIMIZER_ADAPTIVE_STATISTICS(即返回默认设置)之后,两个查询都返回了相同的结果(与预期的一样)。
可以使用以下查询检查这些设置:

SELECT * FROM v$parameter WHERE 1 = 1 AND LOWER(name) LIKE LOWER('optimizer_ad%') ORDER BY 1 DESC;

关于sql - 如果双方都是左连接实体,则where子句中的条件顺序是否相关?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54441507/

10-12 00:22