【发布时间】:2020-08-20 02:08:47
【问题描述】:
这与this question 非常相似,只是一个完整的最小示例。
我有一个只有左连接的简单选择查询(来自非空表)。最后一个左连接恰好是一个空表。
查询应返回 2 个非空行,但只需将其更改为 count(*) 查询即可使其返回 0 作为行数。
相同的 SQL 在 MySQL 和 MSSQL 上都能正常工作(修复 PK 语法后)。
完整(如果未注释可重新运行)示例:
-- DROP TABLE first;
-- DROP TABLE second;
-- DROP TABLE empty;
CREATE TABLE first (
pk int,
fk int
);
ALTER TABLE first
ADD CONSTRAINT PK_first PRIMARY KEY (pk);
CREATE TABLE second (
pk int
);
ALTER TABLE second
ADD CONSTRAINT PK_second PRIMARY KEY (pk);
CREATE TABLE empty (
pk int
);
ALTER TABLE first ADD CONSTRAINT FK_first FOREIGN KEY (fk)
REFERENCES second (pk) ENABLE;
INSERT INTO second (pk)
VALUES (5);
INSERT INTO first (pk, fk)
VALUES (1, 5);
INSERT INTO first (pk, fk)
VALUES (2, 5);
SELECT
COUNT(*)
FROM first
LEFT OUTER JOIN second
ON (first.fk = second.pk)
LEFT OUTER JOIN empty
ON (1 = 1);
最后一个查询在我的机器上返回 0,但是将 count(*) 更改为 * 使其返回 2 行。
谁能重现这个?我的 db_version 是 11.2.0.2。
解释计划似乎看到了应该返回的 2 行:
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
| 2 | MERGE JOIN CARTESIAN| | 2 | 26 | 3 (0)| 00:00:01 |
| 3 | VIEW | | 1 | | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMPTY | 1 | | 2 (0)| 00:00:01 |
| 5 | BUFFER SORT | | 2 | 26 | 3 (0)| 00:00:01 |
| 6 | INDEX FULL SCAN | PK_FIRST | 2 | 26 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
我对动态采样了解不多,但是如果我alter session set OPTIMIZER_DYNAMIC_SAMPLING=0;,那么计划每一步显示82行。
删除主键可以解决 Oracle 上的问题,但这并不是一个合适的解决方案。
将join移到空表中也可以解决问题,但它是带有重言式过滤器的外连接,所以应该是noop。
这实际上是出于某种原因在 Oracle 上的预期行为吗?或者我的服务器只是被窃听了? MSSQL 和 MySQL 都返回 2 作为计数。
编辑:第 2 轮
再添加 2 个表就足够了,并且该错误也在 11.2.0.4 中显示。任何人都可以在更新的 Oracle 版本上重现它吗?
一个在线小提琴here。
CREATE TABLE first (
pk int,
fk int
);
ALTER TABLE first
ADD CONSTRAINT PK_first PRIMARY KEY (pk);
CREATE TABLE second (
pk int,
fk int
);
ALTER TABLE second
ADD CONSTRAINT PK_second PRIMARY KEY (pk);
CREATE TABLE third (
pk int,
fk int
);
ALTER TABLE third
ADD CONSTRAINT PK_third PRIMARY KEY (pk);
CREATE TABLE fourth (
pk int
);
ALTER TABLE fourth
ADD CONSTRAINT PK_fourth PRIMARY KEY (pk);
CREATE TABLE empty (
pk int
);
ALTER TABLE first ADD CONSTRAINT FK_first FOREIGN KEY (fk)
REFERENCES second (pk) ENABLE;
ALTER TABLE second ADD CONSTRAINT FK_second FOREIGN KEY (fk)
REFERENCES third (pk) ENABLE;
ALTER TABLE third ADD CONSTRAINT FK_third FOREIGN KEY (fk)
REFERENCES fourth (pk) ENABLE;
INSERT INTO fourth (pk)
VALUES (50);
INSERT INTO third (pk, fk)
VALUES (10, 50);
INSERT INTO third (pk, fk)
VALUES (11, 50);
INSERT INTO second (pk, fk)
VALUES (5, 10);
INSERT INTO second (pk, fk)
VALUES (6, 10);
INSERT INTO first (pk, fk)
VALUES (1, 5);
INSERT INTO first (pk, fk)
VALUES (2, 5);
SELECT
COUNT(*)
FROM first
LEFT OUTER JOIN second
ON (first.fk = second.pk)
LEFT OUTER JOIN third
ON (first.pk = third.pk)
LEFT OUTER JOIN fourth
ON (third.fk = fourth.pk)
LEFT OUTER JOIN empty
ON (1 = 1);
无论如何,共识似乎是这是过时 Oracle 版本中的一个错误。
【问题讨论】:
-
响应对链接问题的评论,将查询更改为 SELECT COUNT(1) OVER () 立即返回 0 行。
-
Works in Oracle 18(和 12.1) - 很可能是您不受支持(且不再维护)的版本中的错误。
-
哈.. 只是做了同样的事.. @hwnn.. 它真的在 11.2 坏了 - sqlfiddle.com/#!4/f91ac/1
-
刚刚在第二台机器上试了一下,它工作正常。 db_version 11.2.0.4 - 他们很快修复了它。