https://help.kingbase.com.cn/v8/perfor/sql-optimization/sql-optimization-13.html
SQL性能相关的参数较多,具体见下文。在使用时需注意作用范围,可以考虑通过HINT来指定,尽量缩小影响范围。
优化器内部使用基于成本的算法来获取总成本最低的访问路径。在计算成本的公式中,会用到一些定义好的参数因子,这些参数因子会影响到最终计算出出来的总成本,主要包括:
seq_page_cost
数值,默认值为1.0,表示全表扫描时,读取单个数据块的扫描成本。
random_page_cost
数值,默认值为 4.0,表示使用索引扫描时,单个数据块的扫描成本。
cpu_tuple_cost
数值,默认值为0.01,表示读取一个元组时,CPU消耗成本。
cpu_index_tuple_cost
数值,默认值为0.005,表示从索引上读取一个元组时,CPU消耗成本。
cpu_operator_cost
数值,默认值为0.0025,表示执行一个操作符的CPU消耗成本。
这些值是相对的成本值,一般以seq_page_cost为基准。比如random_page_cost为4.0,表示执行计划中计算随机访问的一个数据块页面的开销为顺序访问一个数据块开销的4倍。
其中前2个参数跟I/O有关,后3个跟CPU计算有关。如果服务器更换了磁盘I/O能力更强的硬件,可以尝试调低seq_page_cost和random_page_cost的值,比如调为0.5和2.0。同理CPU消耗成本也可以调高(CPU性能较低时)或者调低(CPU性能显著提升后)。
KingbaseES允许对单个查询关闭特定的优化器特性。如果有事优化器为特定查询选择的执行计划并不是最优的,可以通过设置这些参数强制优化器选择一个更好的执行计划来临时解决这个问题。引起优化器选择错误路径的原因有可能是统计信息更新不及时造成的,可以通过运行Analyze的方式来彻底解决。
扫描类开关:
enable_seqscan
表示是否走全表扫描,当全表数据量非常少或选择率高时使用比较好。
enable_indexscan
表示是否允许走索引扫描,当选择率低时使用比较好。
enable_bitmapscan
表示是否允许走 bitmap 扫描,当多个过滤条件,并且需要扫描数据占整表比索引较大时使用比较好。
enable_tidscan
表示是否允许走 tid 扫描,当指定 ctid 过滤条件时使用比较好。
连接类开关:
enable_hashjoin
表示是否允许走 hash 连接,当数据大都是随机时使用比较好。
enable_nestloop
表示是否允许走 nestloop 连接,当内外表数据量非常小时使用比较好。
enable_mergejoin
表示是否允许走合并连接,当内外表数据基本有序时使用比较好。
其它开关:
enable_hashagg
表示是否允许使用hash的方式来计算Aggregate值。
enable_groupagg
表示是否允许使用group的方式来计算Aggregate值。
enable_sort
表示是否允许使用显式的sort节点。
enable_material
表示是否允许使用物化节点。
以5.3.5 示例环境进行举例,对一个元素比较多的表求聚集值,默认情况下它会使用hash的方式做聚集:
explain select count(*) from t2 where id > 100 group by val; QUERY PLAN ----------------------------------------------------------------- HashAggregate (cost=21924.43..21974.45 rows=5002 width=12) Group Key: val -> Seq Scan on t2 (cost=0.00..16925.00 rows=999886 width=4) Filter: (id > 100) (4 rows)
HashAggregate在少数聚合函数是表现优异,但是很多聚合函数,性能跟消耗的内存差异很明显。尤其是受group by字段的唯一性很明显,字段唯一值越大,hash聚合消耗的内存越多,性能下降剧烈。
而对于GroupAggregate来说,消耗的内存基本上是恒定的,无论group by哪个字段。当聚合函数较少的时候,速度也相对较慢,但是相对稳定。
如果我们禁用hash方式聚集方式,则可以设置enable_hashagg开关:
set enable_hashagg=off; SET explain select count(*) from t2 where id > 100 group by val; QUERY PLAN ------------------------------------------------------------------ GroupAggregate (cost=116570.66..124119.82 rows=5002 width=12) Group Key: val -> Sort (cost=116570.66..119070.37 rows=999886 width=4) Sort Key: val -> Seq Scan on t2 (cost=0.00..16925.00 rows=999886 width=4) Filter: (id > 100) (6 rows)
当通过开关禁止某种扫描、连接、分组、排序或者物化视图方式的时候, 优化器内部将该特性的使用成本加到非常大的一个数值,这样它被执行的可能性就降低了很多, 但是不能完全禁止该特性的使用,取决于最终的成本比较。 比如在某些地方没有索引,关闭enable_seqscan开关,依然会选用全表扫描。 为了减少开关的禁止打开对所有SQL语句的影响,上面的操作尽可能使用HINT来控制。
当一个查询涉及到的表的总数很多的时候(比如超过12个),则会有无数的路径组合。KingbaseES在这种情况下,为了避免产生大量的可选路径消耗大量CPU,采用启发式算法来搜索一定范围内的可能的访问路径,这就是基因查询优化(GEQO)。GEQO选出来的路径结果有可能是随机的,因此在此情况下生成的执行计划会有不确定性。
跟基因查询相关的比较重要的参数有3个:
geqo
Bool值,是否允许使用基因查询,默认为true。关闭基因查询虽然能够得到最佳的访问路径,但是其生成执行计划的时间有可能会变得很大。
geqo_threshold
整数,当关系表的个数超过该值的时候,启用基因查询来做路径选择,默认为12。当关系表的个数少于该值的时候,优化器会穷举所有可能的访问路径并从中选出最佳的结果。
geqo_effort
整数,控制基因查询里规划时间和查询规划有效性之间的平衡,即在效率和结果之间做选择,默认为5,可以选择1~10之间的数。选的数值越大,则优化器花费更多的时间,当然选到更优的访问路径概率也更大。
还有4个参数:geqo_pool_size, geqo_generations, geqo_selection_bias, geqo_seed可以进一步控制基因查询的行为,可以查看 KingbaseES服务器配置参数参考手册 。
work_mem
原理:内部排序和哈希操作可使用的工作内存大小。该内存是在开始使用临时磁盘文件之前使用的内存数目。
应用范围:数据比较多大的情况,主要和排序的数据有关系,排序数据越大,设置的就越大,比如16g内存,tpch测试,单用户10g规模数据,设置2g的work_mem。数值以kB为单位的,缺省是1024(1MB)。索引扫描不用work_mem。
注意
对于复杂的查询,可能会同时并发运行好几个排序或者哈希操作, 每个都会使用这个参数声明的这么多内存,然后才会开始求助于临时文件。同样,好几个正在运行的会话可能会同时进行排序操作。因此使用的总内存可能是work_mem 的好几倍。ORDER BY、DISTINCT 和 mergejoin 都要用到排序操作,而哈希操作在哈希连接、哈希聚集和以哈希为基础的 IN 子查询处理中都会用到。
maintenance_work_mem
原理:在维护性操作(比如 VACUUM, CREATE INDEX, ALTER TABLE ADD FOREIGN KEY 等)中使用的最大的内存数。
应用范围:在维护性操作(比如 VACUUM, CREATE INDEX, ALTER TABLE ADD FOREIGN KEY 等)调整大小,默认是16MB,比如创建索引的索引数据很大,比如10g,如果内存允许 就可以调整这个参数1g,一般在灌数的时候调大,灌数完毕测试时再调小。
注意
因为在一个数据库会话里,任意时刻只有一个这样的操作可以执行, 并且一个数据库安装通常不会有太多这样的工作并发执行, 把这个数值设置得比work_mem更大是安全的。 更大的设置可以改进清理和恢复数据的速度,一般测试时不能调的过大。
temp_buffers
原理: 存储临时信息时使用的最大块数。
应用范围:最小值为100,最大值为INT_MAX/2,默认值为1024,执行器使用此区域存储临时表。
shared_buffers
原理:数据库服务器使用的共享内存缓冲区的数量,主要用于缓存数据,根据需求一般不能设置超过80%的内存,但至少是20%。
应用范围:数据库本身,查询的数据量比较大,比较频繁使用到。
注意
KingbaseES 使用内存总大小为:
shared_buffers(数据) + wal_buffers(日志 )+ maintenance_work_mem(创建索引排序时使用)+ n*work_mem(n为并发做排序的连接数)+ 服务进程上下文使用的内存(无法精确估计大小)+ m*thread_stack_size(thread_stack_size 为进程栈的大小,KingbaseES 默认为 1MB;m 为当前连接数);
由于 32bit 平台的用户进程内存寻址空间较小(window 为 2G、linux为3G),所以这些内存的设置在 32bit 平台上的设置不能过大,防止内存溢出。
cursor_tuple_fraction
0.1~1.0之间的一个数值,默认值是 0.1。更小的值使得优化器偏向为游标快速返回第一条记录,但是可能需要很长时间来获取所有行。更大的值强调总体代价。比如设置为 1.0,游标将和普通查询完全一样地被规划,只考虑总体代价最低,而不考虑前几行会被多快地返回。
from_collapse_limit
整数,默认值为8。如果生成的FROM列表不超过这么多项,规划器将把子查询融合到上层查询。较小的值可以减少规划时间,但是可能会生成较差的查询计划。将这个值设置为geqo_threshold或更大,可能触发使用 GEQO 规划器,从而产生非最优计划。
join_collapse_limit
如果查询重写生成的FROM后的项目数不超这个数,那么优化器器将把显式JOIN(除了FULL JOIN)结构重写到 FROM项列表中。较小的值可减少规划时间,但是可能会生成差些的查询计划。默认情况下,这个变量被设置成和from_collapse_limit相同,这样适合大多数使用。将这个值设置为geqo_threshold或更大,可能触发使用 GEQO 规划器,从而产生非最优计划。