GreenPlum在PG优化器下针对列存表执行单列聚集时(无过滤条件),不管聚集中包含多少列,都需要将所有列扫描上来。比如select avg(id1) from t1。扫描时,不仅将id1列的数据读取出来,还会将其他列的数据也读取上来。一旦列里有变长数据,无疑会显著拖慢扫描速度。
这是怎么做到的?在哪里设置的需要读取所有列?以及为什么要这么做?
1、首先,需要知道如何确定扫描哪些列。GP的aocs_getnext函数中columScanInfo信息有投影列数和投影列数组,由此决定需要读取哪些列值:
2、接着就需要了解columScanInfo信息来自哪里
aoco_beginscan_extractcolumn函数对列进行提取,也就是targetlist和qual:
3、顺藤摸瓜,targetlist和qual来自哪里?
在SeqNext函数中,可以看到SeqScan计划节点的targetlist和qual。由此可以知道他们来自执行计划中:
4、这样,就需要知道执行计划如何生成,targetlist链表是如何初始化的
create_plan是执行计划的生成入口。如果select id1 from t1,无聚合,那么入口的flag标签是CP_EXACT_TLIST,进入create_scan_plan后,use_physical_tlist函数依据该标签立即返回false,使用build_path_tlist构建targetlist,仅获取表id1列:
plan = create_plan_recurse(root,best_path,CP_EXACT_TLIST);
plan = create_scan_plan(root,best_path,flags)
而使用select avg(id1) from t1时,执行计划的首节点是AGG:
plan = create_plan_recurse(root,best_path,CP_EXACT_TLIST);
到扫描节点处的标签是CP_LABEL_TLIST了,所以use_physical_tlist函数返回true,通过build_physical_tlist函数构建targetlist链表,该函数将所有列都构建了进去。
为什么要这么做呢?
5、openGauss的聚合下列扫描仅扫描1列,它是如何做到的?
通过create_cstorescan_plan构建targetlist,可以看到它将传进来的tlist释放掉了,通过函数build_relation_tlist重新构建,此函数构建时,仅将聚合列构建进去。