注册

DM8中视图/CTE内层DISTINCT的部分去重列未被外层引用时,结果行被错误合并

Xy.Xie_WHU 2026/07/12 318 1

为提高效率,提问时请提供以下信息,问题描述清晰可优先响应。
【DM版本】:
DM Database Server 64 V8
DB Version: 0x7000d
03134284552-20260414-322369-20221
Msg Version: 1
Gsu level(5) cnt: 102
DM 管理工具
【操作系统】:
Windows 11 64 位
【CPU】:
Intel x86_64
【问题描述】*:
相同查询通过 CTAS 物化到全局临时表后,能够正确保留两条记录。

本例中,两条源记录经过内部查询后分别为:
VC_0 = {"a":4,"b":"h4"}
VC_1 = NULL
VC_2 = 1
VC_3 = 32
以及:
VC_0 = {"nested":{"x":null}}
VC_1 = NULL
VC_2 = 1
VC_3 = 32

两条记录的 VC_0 不同,因此对于以下四列 DISTINCT:
SELECT DISTINCT VC_0, VC_1, VC_2, VC_3
它们应当被保留为两条不同记录。

外层查询只输出:
SELECT VC_3, VC_1, VC_2
外层没有使用 DISTINCT,因此投影后即使两条结果显示完全相同,也仍应保留两行。

实际结果为:
视图: 1行
CTE: 1行
CTAS临时表: 2行
怀疑优化器在视图或 CTE 展开过程中,错误地裁剪了外层未引用的 VC_0,并将 DISTINCT 从原来的四列错误改写为仅针对外层使用的三列去重,导致两条不同记录被错误合并。

复现脚本
CREATE SCHEMA database0;
SET SCHEMA database0;
drop table if EXISTS T_DM_6651;
drop view if EXISTS V_DM_6651;
drop table if EXISTS TEMP_DM_6651;
drop table if EXISTS TEMPOCPR_DM_6651;

CREATE TABLE T_DM_6651 (C0 CHAR(2), C1 BIGINT, C2 JSON, C3 INTEGER, C4 NUMERIC(38,38), C5 FLOAT, C6 REAL, C7 BLOB, DM_ROW_ID BIGINT NOT NULL);

INSERT INTO T_DM_6651 (C0, C1, C2, C3, C4, C5, C6, C7, DM_ROW_ID) VALUES (' ', '4', '{"a":4,"b":"h4"}', NULL, -0.220817161263, 0.2, NULL, 0xff, 1);
INSERT INTO T_DM_6651 (C0, C1, C2, C3, C4, C5, C6, C7, DM_ROW_ID) VALUES ('', '1', '{"nested":{"x":null}}', NULL, -0.915100832141, 949172.250220101, 549941.024175025, 0xb505e08a22f7011c297ffc561642cc322b12e28b75f1143d36e3d33c3bf10e658818c7301740ec8e62051be6a1cdd3f294a4477e3ad926, 10);

CREATE VIEW V_DM_6651 (VC_0, VC_1, VC_2, VC_3) AS SELECT DISTINCT C2 AS VC_0, ROUND(C3, 2) AS VC_1, SIGN(C1) AS VC_2, ASCII(SUBSTR(C0,1,1)) AS VC_3 FROM T_DM_6651;
SELECT VC_3, VC_1, VC_2 FROM V_DM_6651 ORDER BY VC_3 ASC NULLS LAST, VC_1 ASC NULLS LAST, VC_2 ASC NULLS LAST LIMIT 20;
-- row=1

WITH CTE AS (SELECT DISTINCT C2 AS VC_0, ROUND(C3, 2) AS VC_1, SIGN(C1) AS VC_2, ASCII(SUBSTR(C0,1,1)) AS VC_3 FROM T_DM_6651) SELECT VC_3, VC_1, VC_2 FROM CTE ORDER BY VC_3 ASC NULLS LAST, VC_1 ASC NULLS LAST, VC_2 ASC NULLS LAST LIMIT 20;
-- row=1

CREATE GLOBAL TEMPORARY TABLE TEMP_DM_6651 ON COMMIT PRESERVE ROWS AS SELECT DISTINCT C2 AS VC_0, ROUND(C3, 2) AS VC_1, SIGN(C1) AS VC_2, ASCII(SUBSTR(C0,1,1)) AS VC_3 FROM T_DM_6651;
SELECT VC_3, VC_1, VC_2 FROM TEMP_DM_6651 ORDER BY VC_3 ASC NULLS LAST, VC_1 ASC NULLS LAST, VC_2 ASC NULLS LAST LIMIT 20;
-- row=2

结果汇总
查询方式 实际行数 预期行数
视图 1 2
CTE 1 2
CTAS全局临时表 2 2

SQL语义说明
正确的逻辑执行过程应为:

  1. 对 VC_0、VC_1、VC_2、VC_3 四列执行 DISTINCT;
  2. 因为两条记录的 VC_0 不同,所以保留两条记录;
  3. 外层投影删除 VC_0;
  4. 投影后的两行虽然内容相同,但外层没有 DISTINCT;
  5. 最终仍应返回两行。

不能将其错误改写为:

  1. 因为外层未引用 VC_0,先裁剪 VC_0;
  2. 只对 VC_1、VC_2、VC_3 执行 DISTINCT;
  3. 将两条记录错误合并为一条。
    外层列裁剪不能改变内层 DISTINCT 的去重键及查询结果的重复度。

该问题改变了结果行数,属于查询结果正确性问题。

回答 0
暂无回答
扫一扫
联系客服