openGauss 的 SQL 引擎在版本中做了哪些优化?
查询执行能力对数据库来说至关重要,这直接决定了查询语句生成的执行计划以何种方式进行执行,如果哪个执行算子的执行表现不好,将会对数据库的整体性能产生极大的影响。同时,执行算子的实现也极大考验一款数据库的工程实现能力。为此,openGauss 数据库在 3.1.0 版本中,进一步优化了当前的部分执行算子,并希望通过优化执行算子的实现,来提高数据库的整体表现。下面介绍一下在该版本中,openGauss 数据库都做了哪些 SQL 引擎的优化。
分区表页面估算优化
目前分区表的统计信息,代价模型使用的是普通表的机制,由于分区表和普通表结构上的不同,所以不能完全依赖普通表的机制去处理分区表的代价问题。由于分区表存在天然的分区优势,所以在分区剪枝的情况下,SQL 语句在查询过程中不会访问所有分区。对于分区存在剪枝的场景,分区表页面统计时就不能单纯的统计所有分区的页面。在剪枝场景下只需要统计剪枝后的分区页面数即可。由于目前分区表没有统计每个分区的页面数,因此基于均匀性假设(分区页面不倾斜),用以下公式估算分区页面数:
剪枝后分区页面数 = 分区表总页面数 * (剪枝后分区数 / 总分区数)
通过改进分区表页面的估算方法,可以优化数据库的表扫描性能,从而提升数据库在分区表场景中的执行表现。该特性可通过 GUC 参数 partition_page_estimation 控制。
Partition Iterator 算子优化
在 openGauss 数据库中,分区表是依靠分区迭代算子进行分区扫描的,迭代算子控制每一个分区依次扫描数据。当分区剪枝结果只有一个分区时,迭代算子已经失去了迭代器的作用,在此情况下消除迭代算子,可以避免执行时迭代算子计算的开销。由于执行器的 pipeline 架构,迭代算子会被重复执行,在数据量比较大的场景下消除迭代算子的收益将十分可观。故在该版本中,我们通过对迭代算子进行改进,消除分区扫描时的 overhead,进而提升数据库在该场景下的执行性能。该特性可通过 GUC 参数 partition_iterator_elimination 控制。
SeqScan 算子优化
开启该优化,当用户不采集 cpu 信息时(例如 explain cpu off),关闭 cpu 信息采集功能(例如执行 CPUUsageGetCurrent 函数),从而减少 cpu 执行周期。该特性不影响正常的 cpu 信息采集,相关监控视图和系统函数不受影响。同时,从磁盘读取数据时,优化 mdread 机制,减少冗余的 checksum 检查,进而通过消除无用的操作来提升数据库性能。该特性可通过 GUC 参数 enable_seqscan_fusion 控制。
上面的三个方面是该版本对 openGauss 数据库的 SQL 引擎的优化,后续我们还会对更多的 openGauss 数据库内部执行逻辑进行优化,敬请关注。