Redshift执行INNER JOIN未过滤数据返回错误COUNT结果如何解决
问题根因
该问题是Redshift优化器触发了**错误的连接消除(Join Elimination)**规则导致:
优化器误判usr_ykhvainitski.hub_users表的user_hash_id字段存在唯一非空约束,且usr_ykhvainitski.lnk_users_to_accounts表的user_hash_id是关联前者的外键,因此判定INNER JOIN不会过滤左表任何行,同时你使用count(*)不需要右表的任何字段,所以直接跳过右表扫描,直接返回左表的总行数,完全忽略JOIN的过滤逻辑,属于ra3系列节点已知的优化器误判问题,和统计信息、分布键配置无关。
解决方案
方案1:改写COUNT逻辑,强制依赖右表字段
将count(*)替换为统计右表的关联字段count(u.user_hash_id),或者在WHERE子句中追加无实际过滤效果的右表字段校验条件,强制优化器必须扫描右表获取对应字段值,无法触发连接消除。
修改后的查询示例:
SELECT count(u.user_hash_id) FROM usr_ykhvainitski.lnk_users_to_accounts l , usr_ykhvainitski.hub_users u WHERE l.user_hash_id = u.user_hash_id;
执行后即可得到正确的匹配行数:24256599 - 19575195 = 4681404 行。
方案2:会话级关闭连接消除优化参数
执行查询前先运行如下命令,临时禁用当前会话的连接消除优化规则,不需要修改原有查询语句即可得到正确结果:
SET enable_join_elimination = off;
如果需要长期生效,可联系集群管理员修改集群参数组中的对应配置。
方案3:清理错误的约束元数据
检查usr_ykhvainitski.hub_users表的user_hash_id字段是否被错误添加了PRIMARY KEY或者UNIQUE NOT NULL约束,如果存在不符合实际数据的约束,删除该约束即可从根源避免优化器误判。
内容的提问来源于stack exchange,提问作者Yauheni Khvainitski

