只是调查一个mysql查询,它返回的记录比它应该返回的要多。
基本查询是:
SELECT
a.id AS parent_id,
b.id AS child_one_id,
c.*
FROM
parent AS a
LEFT JOIN child_one AS b ON a.id = b.parent_id
LEFT JOIN child_two AS c ON (
a.id = c.parent_id
AND c.user_id = '1234'
AND c.deleted_at IS NULL
)
WHERE (
a.user_id = '1234' OR c.parent_id IS NOT NULL
);
i、 e.父表与两个子表保持连接,两个子表之间没有指定关系,并且只对用户拥有记录或用户通过子表2链接到记录的结果应用筛选器。
据我对左联接的理解,如果数据库在右侧表中找不到匹配的记录,它将生成一个“空”记录,所有值都设置为null。
但是,在本例中,它生成了一些记录,其中“空”记录似乎是通过隐式类型转换生成的。
# parent_id, child_one_id, id, parent_id, created_at, updated_at, deleted_at
27 , 29 , , , , ,
27 , 32 , 0, 0, 0000-00-00 00:00:00, 0000-00-00 00:00:00,
27 , 47 , 0, 0, 0000-00-00 00:00:00, 0000-00-00 00:00:00,
30 , 26 , , , , ,
30 , 46 , 0, 0, 0000-00-00 00:00:00, 0000-00-00 00:00:00,
i、 e.对于某些记录,它为child\u two生成了一个“null”记录,但是对于其他记录,它似乎执行了类型转换,为child\u two创建了一个“zeroed”记录。
(在任何人询问之前,不,child\u two中没有任何id为零的记录!)
我还证明了有两种方法可以阻止生成归零记录:
1) 从查询中删除子项1
2) 将孩子的加入改为“ LEFT JOIN child_one AS b ON (a.id = b.parent_id AND b.user_id = '1234')
"
但是,这并不能解释为什么会触发这种类型转换,或者为什么只对某些记录触发这种类型转换。可悲的是,我尽我最大的努力去运用我的googlefu,却没能找到任何可能的解释。
因此,虽然我已经找到了解决这个问题的方法,但我仍然非常想了解为什么/如何创建“归零”记录—我们使用 LEFT JOIN x ... WHERE x.id IS NULL
“在很多地方!
更新:我已经设法在一些临时表克隆上复制了这个问题,减少了列的数量,并且每个表中的记录数量最少。
http://sqlfiddle.com/#!9/faa3d0/1号机组
通过上面的sql,我能够在生产服务器上的多个模式上重现这个问题。但是,它不会发生在我们的测试或开发服务器上,也不会发生在sqlfiddle上。
所以这似乎是特定于我们的生产服务器。
有趣的一点是,如果我把主索引放到child_two上,问题就不会发生了。尽管解释计划显示查询仍然使用“job\ id”索引来检索数据。
目前,我们正在运行以下mysql版本:
生产:5.7.11-4-log(percona服务器(gpl),版本'4',版本'5c940e1')
测试:5.7.21-21(percona服务器(gpl),版本'21',版本'2a37e4e')
dev:5.7.21-21(percona服务器(gpl),版本'21',修订版'2a37e4e')
sqlfiddle在mysql 5.6上运行。
这表明,这是percona 5.7流中的一个问题,在5.7.11-4版本之后的某个时间点上解决了这个问题。但是,我在发行说明中看不到任何潜在的候选人。
我们将在不久的将来升级我们的生产服务器,所以希望这个问题将得到解决。同时,如果任何人能够确定解决问题的补丁程序(和/或可用于缓解问题的任何配置),那将非常感谢!
暂无答案!
目前还没有任何答案,快来回答吧!