一样的语句,一样的表,在mysql、tidb中查出结果不一样,mysql结果正确

SELECT a.id AS “id”,
parent AS “pid”,
role_name AS “name”,
(SELECT sir.role_id
FROM t_sys_staff_inst_role sir
INNER JOIN t_sys_staff s
ON sir.staff_id = s.id
WHERE sir.institution_id = 100002
AND sir.staff_id = 51019
AND sir.role_id = a.id) AS checked
FROM t_sys_role a
WHERE a.platform_code = ‘ahis’
ORDER BY orders ASC;
以上语句在mysql中执行结果正确,在tidb中执行结果不正确


  1. 请问 tidb 版本是哪个?
  2. 请反馈建表语句,我们测试下,多谢。

tidb4.0.4,我把创建表语句及里面的数据发你。sql0911.zip (473.5 KB)

v4.0.4 存在问题,升级到 v4.0.5 即可,问题已经修复。

其实我们不关心这个具体问题,想知道什么原因导致,是不是我们以后上生产了还碰到类似问题,能说明原因,我们心里有底
或者能告诉我们4.0.5通过修复什么BUG解决4.0.4这个问题的,我们自己去查一下问题原因

hi 这个问题是因 4.0 引入的 PointGet as datasource 优化(所以如果您使用的是 3.0 不会有这个问题), table:t_sys_staff 将使用性能更好的 PointGet 算子作为 t_sys_staff_inst_role 和 t_sys_staff 进行 join 的 probe 表

MySQL [test]> explain SELECT a.id AS id, parent AS pid, role_name AS name, (SELECT sir.role_id FROM t_sys_staff_inst_role sir INNER JOIN t_sys_staff s ON sir.staff_id = s.id WHERE sir.institution_id = 100002 AND sir.staff_id = 51019 AND sir.role_id = a.id) AS checked FROM t_sys_role a WHERE a.platform_code = 'ahis' ORDER BY orders ASC;
+--------------------------------------------+---------+-----------+----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+
| id                                         | estRows | task      | access object                                                              | operator info                                                                                             |
+--------------------------------------------+---------+-----------+----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+
| Projection_14                              | 0.08    | root      |                                                                            | test.t_sys_role.id, test.t_sys_role.parent, test.t_sys_role.role_name, test.t_sys_staff_inst_role.role_id |
| └─Sort_15                                  | 0.08    | root      |                                                                            | test.t_sys_role.orders:asc                                                                                |
|   └─Apply_18                               | 0.08    | root      |                                                                            | CARTESIAN left outer join                                                                                 |
|     ├─TableReader_21(Build)                | 0.08    | root      |                                                                            | data:Selection_20                                                                                         |
|     │ └─Selection_20                       | 0.08    | cop[tikv] |                                                                            | eq(test.t_sys_role.platform_code, "ahis")                                                                 |
|     │   └─TableFullScan_19                 | 79.00   | cop[tikv] | table:a                                                                    | keep order:false, stats:pseudo                                                                            |
|     └─MaxOneRow_22(Probe)                  | 1.00    | root      |                                                                            |                                                                                                           |
|       └─HashJoin_24                        | 0.00    | root      |                                                                            | CARTESIAN inner join                                                                                      |
|         ├─IndexLookUp_31(Build)            | 0.00    | root      |                                                                            |                                                                                                           |
|         │ ├─IndexRangeScan_28(Build)       | 4.00    | cop[tikv] | table:sir, index:idx_staff_instrole_staff_instid(staff_id, institution_id) | range:[51019 100002,51019 100002], keep order:false                                                       |
|         │ └─Selection_30(Probe)            | 0.00    | cop[tikv] |                                                                            | eq(test.t_sys_staff_inst_role.role_id, test.t_sys_role.id)                                                |
|         │   └─TableRowIDScan_29            | 4.00    | cop[tikv] | table:sir                                                                  | keep order:false                                                                                          |
|         └─Point_Get_32(Probe)              | 1.00    | root      | table:t_sys_staff, index:PRIMARY(id)                                       |                                                                                                           |
+--------------------------------------------+---------+-----------+----------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+
13 rows in set (0.001 sec)

但如上面看到的 t_sys_staff_inst_role 和 t_sys_staff 的 join 组合算子将被 t_sys_role 外表的每行数据进行 apply join,因此 t_sys_staff 表的 PointGet 算子将被多次 Open/Close,但 4.0.5 之前的 PointGet 算子的 Close 并没有做很完善清理重置操作(3.0 没问题是因为 Point 不可能会在 apply 下出现),导致非首次 apply probe 将返回上一次的数据,导致看到都是 NULL 的问题

这个问题会在 4.0.0 - 4.0.4 版本中 apply probe 侧孩子有 point-get 算子的情况出现,建议升级到 4.0.5 可以避免出现类似问题

修复细节见 https://github.com/pingcap/tidb/pull/19046/files#diff-df02d02a3dd97c99ecb50a845c2c4b46R127

请问你这个执行计划输出格式很好,我的换行,你是这么做的

应该是这个太长了,我在终端里也换行,但复制处理张贴到这里用 markdown 代码标签 刚好不换行 :smiley: