batchCop 方式查询包含生成列的表出错

【 TiDB 使用环境】生产环境 /测试
【 TiDB 版本】7.1.2
【复现路径】

  1. 创建一个包含 virtual 生成列的表
  2. 设置tiflash副本数为1
  3. 插入几条数据
  4. 设置使用执行引擎。set tidb_isolation_read_engines = ‘tikv,tiflash’;
  5. 执行带排序的 select 查询,查询结果中包含前面创建的生成列(使用 * 或显示指定生成列的名称都一样), 查询语句中包含order by 子句 和 limit子句,没有offset或者offset值为0

【遇到的问题:问题现象及影响】
按以上复现路径执行完后,服务端返回类似下面的错误信息

Error Code: 1105
Not found column table_scan_1 in block. There are only columns: table_scan_0, table_scan_2

【资源配置】进入到 TiDB Dashboard -集群信息 (Cluster Info) -主机(Hosts) 截图此页面
【附件:截图/日志/监控】

附上创建表的语句和执行的sql
– 创建表
CREATE TABLE generate_demo (
id BIGINT(20) NOT NULL,
created_at DATETIME NOT NULL,
is_removed TINYINT(1) NOT NULL,
updated_at DATETIME DEFAULT NULL,
__since_at DATETIME GENERATED ALWAYS AS (updated_at) VIRTUAL,
PRIMARY KEY (id)
);
– 设置tiflash副本
ALTER TABLE test.generate_demo SET tiflash replica 1;

– 初始化数据
INSERT INTO generate_demo
(id, created_at, is_removed, updated_at)
VALUES (1, NOW(), 0, NULL),
(2, NOW(), 1, NOW())
;

– 查询

SELECT *
FROM generate_demo
ORDER BY created_at ASC
LIMIT 100;

【备注】

我本地开发环境还有一个 tidb 6.1的版本,同样的执行方式就能正常返回结果
另外补充几个在7.1版里能正常返回结果的现象:

  1. select 语句中只包含order by或者只包含limit 两者之一都能正常返回结果。
  2. order by 和 offset子句都同时存在,且offset 设置为大于0的值也能正常返回
  3. 再次试验的结果证实了只有 virtual 方式的生成列才会出问题,stored 的生成列不会出错。但是修给一个表新增列的时候只支持 virtual 的生成列

继续验证后补充信息:

  1. 查看了执行计划后发现出错的时候实际使用的是batchCop方式,并不是mpp方式,这个是之前没有发现的。启用 tidb_enforce_mpp 后之前一直以为默认会使用mpp方式,结果证明并不一定是,还得得看执行计划才能确认。执行explain + 前面出错的查询语句输出信息如下

    执行explain analyze + 前面出错的查询语句,报的错误跟直接执行前面出错的查询语句报的错误一样
  2. 当tidb_isolation_read_engines 设置为‘tiflash’时,执行方式改为 cop 方式

    在此模式下sql是能正常执行的
1 个赞

这是那个空间不足,权限不足的错不

看着像bug

应该不是
只是一个查询语句,表里就一两条数据也会这样,内存和磁盘都是足够的。而且不管哪个环境都能复现
我用的是root账号,权限已经是最高的了

select后面的列名只有updated_at会不会报错?
update的值不取null会不会出错?

你说的这种情况不会
描述里【复现路径】第5点已经提到了,只要结果集里包含生成列字段就会出错,不包含不会出错

select /*+ read_from_storage(tiflash[generate_demo]) */ * from generate_demo;
虚拟列导致tiflash没有正确存数据。强制走tiflash就可以看到。

不带limit 和 order by 不加hint 直接查询也没有问题,加上order by 和 limit 就会出错。请参考前面的复现步骤和 提供的sql示例

SELECT /*+ read_from_storage(tiflash[generate_demo]) */ *
FROM generate_demo
ORDER BY created_at ASC
LIMIT 100;

那有可能真的是bug。
存储生成列没有问题是因为真的生成了列并存储了数据,
而虚拟生成列是在查询时才“生成”列名与数据,
像视图与物化视图的关系。

如果在TiKV上查询没有问题的话,可能在TiFlash上生成的解析没有正确地生成虚拟列名。

只使用tikv的话怎么写查询都是没有问题的

我感觉是虚拟生成列在tiflash里没有真正生成出来,查询结果又需要返回这列信息,但从tiflash里找不到。又没有把虚拟生成列字段补上导致处理结果集字段映射的时候缺少列

从出错信息里大概能猜出点眉目来。
表里有4个普通字段,一个生成列字段,tiflash里只有table_scan_0~3,刚好少一个 table_scan_4

而且在6.1上没有问题,感觉更像bug了。
mysql没有这个问题,可能是TiDB在Mysql引擎的实现上出了问题。

是的,我可能没有表达清楚。强制走tiflash是为了验证你发的情况,说明数据存在tikv中是没有问题的,存在tiflash中有问题,应该是tiflash对虚拟列这个支持有问题,要解决得提issue

已经在github上提过了,欢迎围观
https://github.com/pingcap/tiflash/issues/8787

1 个赞

描述的挺清楚的,感觉大概率是个和生成列相关的bug。