本文旨在分析Kingbase中基于代价的查询优化的基本概念与代价模型,为自己以后工作提供一个笔记。同时该文章也适用于学习和开发PostgreSQL的同学
数据库优化器基本上都支持逻辑优化和物理优化。逻辑优化的核心是代数的等价转换。基于代价的查询优化技术是物理优化的一个重要部分。合理的代数等价转换和代价估算是数据库优化器的一项重要功能。
基于代价的查询优化技术(Cose-Based Optimizaton,CBO),基于对数据库中的大量数据进行统计(抽样统计)得到的统计信息,考虑系统的各种参数(缓冲区大小,数据分布,存取路径等),优化器可以类似于准确的估计出各种查询计划所需要的资源消耗和时间开销,从而选择出一条最合适的执行计划。
统计信息是基于代价的查询优化技术的基础,也是计算查询代价的原始材料,代价估算的过程非常依赖数据库的统计信息,统计信息的准确度直接影响到了查询优化的准确性。Kingbase为了支持基于代价的优化(CBO)提供了统计信息功能,主要信息包含包括两个方面:
优化器在计算表的扫描成本时,需要知道表的基本数据,例如元组的总数,占据磁盘块的页面数等信息。这些信息主要保存在sys_class系统表中,主要包含两个主要的字段:reltuples
和relpages
。
reltuples :表示该表或者索引在磁盘中的元组数。
relpages:表或者索引占用的磁盘块数。
列统计信息是指对表中的每一列的统计信息,主要存储在sys_statistic系统表中,它负责从多个角度描述该列的数据概况信息。
stanullfrac、stawidth、stadistinct
等字段。most_common_vals、most_common_freqs、histogram_bounds
等字段。stanullfrac:列的项为空的比例。
stawidth:非空项的平均存储宽度,以字节计。
stadistinct:唯一值的个数或者比例,如果全唯一则0,>0表示个数,<0,表示比例。
most_common_vals:列中最常用值的一个列表。
most_common_freqs:最常用值的频率。
most_common_elems:最经常出现的非空元素列表。
most_common_elem_freqs:最常用非空元素值的频率。
histogram_bounds:将列值划分成大小接近的直方图。
elem_count_histogram:非空元素值计数的一个直方图。
其他字段及其含义可以参考Kingbase相关的文档
Kingbase主要通过两种方式收集统计信息,一种是通过VACUUM、ANALYZE操作进行采样统计,另一种方式是通过利用一些DDL语句执行的副产品得到统计信息,例如在创(重)建索引的时候,利用建立索引需要对属性进行扫描和排序的特点,可以收集reltuples和stadistinct。
Kingbase通过(等频)直方图,最频值(MCV)和空值率等统计信息来进行选择率的估算。
选择率 = 约束条件过滤后的元组数/过滤前的元组的总数。
直方图简介
直方图是被广泛应用的一种统计图表,主要用于代价的选择率的选择上,根据统计方法的不同,直方图可分为:
最频值(MCV)简介
最频值(MCV)统计列中出现频率最高的N个数值和每个数值出现的频率(MCVF)
1、主动收集
用户可以通过执行VACUUM ANALYZE或者ANALYZE语句让Kingbase通过采样的方法收集统计信息。
2、自动收集
自动收集依赖于autovacuum进程,autovacuum launcher会定期或者根据触发条件进行触发,触发后将进行统计信息的统计。
现在磁盘关系数据库(DBMS)的代价模型主要是基于磁盘IO和CPU计算开销建立的,其中磁盘IO开销又占据了开销的主要部分,基于代价的查询优化技术为数据库的每种物理运算符都建立了相关的代价模型,代价估计的准确性直接影响了查询计划的好坏。
代价常量以一次IO为标准进行衡量的,也就是说一次IO的值为1.0,其他的代价常量都是以它作为参考进行设置的,该值是一种相对值,针对特殊的硬件需要进行特殊的处理。
seq_page_cost (floating point) 一次顺序扫描获取磁盘页面的开销,默认是1.0。
random_page_cost (floating point) 一次随机获取一个磁盘页面的开销,默认值4.0
cpu_tuple_cost (floating point) 处理每一行的CPU代价估计。默认值是 0.01。
cpu_index_tuple_cost (floating point) 一次索引扫描中处理每一个索引项的代价估计。默认值是 0.005。
cpu_operator_cost (floating point) 一次查询中处理每个操作符或函数的代价估计。默认值是 0.0025。
parallel_setup_cost (floating point) 启动并行工作者进程的代价估计。默认是 1000。
parallel_tuple_cost (floating point) 从一个并行工作者进程传递一个元组给另一个进程的代价估计。默认是 0.1。
顺序扫描代价模型
seq_page* relpages
。(seq_page_cost为代价模型常量中一次顺序扫描的代价,relpages为sys_class中关于表的页面数的统计)。cpu_tuple_cost
)。2、将内存中的元组根据过滤条件进行过滤操作(cpu_operator_cost
)。顺序扫描模型:seq_page* relpages + (cpu_tuple_cost +cpu_operator_cost) * reltuples
索引扫描代价模型
索引扫描的代价模型主要包括:处理索引页产生的IO和CPU代价 + 处理数据页产生的IO和CPU代价。
random_page_cost
* pages_fetchedcpu_index_tuple_cost
* numIndexTuplescpu_operator_cost
*filterednumTupleindex_qual_cost
.per_tuple - cpu_operator_cost
* 过滤条件的个数)索引扫描代价模型(单表扫描): indexStartupCost + index->pages * random_page_cost + * (cpu_index_tuple_cost + cpu_operator_cost * 过滤条件数)
注意:
上面的代价计算不包含数据页的扫描代价,数据页的扫描代价基于数据页的两个极端情况之间。数据页的扫描代价有两个极端情况。
1、如果数据是有序的,那么IO代价为一次随机IO+其余的顺序IO。
IO_cost = random_page_cost + (page_fetched -1) * seq_page_cost
2、如果数据页是无序的,那么IO代价为页面数*随机IO的代价常量
IO_cost = random_page_cost * page_fetched
上面的计算也没有考虑缓存的影响。
1、统计信息本身具有偏差性,例如:基于表的统计信息是根据ANALYZE或者VACUUM等操作通过扫描部分信息进行估算的,不能代表真实的数据,具有一定的偏差性。
2、统计信息具有延后性,即使统计信息刚刚进行了更新操作,它的数据也是延后的,并不是实时的数据。所以与当前的实际数据具有一定的差异。
这会导致查询引擎在基于该统计信息计算最优查询访问路径时候的偏差,从而导致最后选择计划的偏差。
3、代价模型中不恰当的假设条件。不同的硬件系统对应的磁盘IO的读写性能是不相同的。例如:磁盘阵列(RAID)和固态硬盘(Solid State Disk)作为数据存储设备,写操作、顺序读取和随机读取的代价都有显著的不同。
4、枚举算法的有限性。基于动态规划算法和遗传算法等算法对于最优路径的选择具有一定的限制。比如:遗传算法中选择的最优路径有可能是当前选择的路径中的最优路径,其他排除掉的路径到最后有可能是最优的。虽然这种概率比较低。
参考资料:
www.postgresql.org
help.kingbase.com.cn
【更多人大金仓数据库信息,详见:[https://help.kingbase.com.cn]】