|
|
Greenplum Database 管理员指南 V6.2.1
从执行计划可以看到,Orca优化器,根据失真的统计信息生成了错误的执行计划,
在扫描完数据之后,就使用a字段进行数据重分布,这注定会发生计算倾斜。执行计划
中,选择了GroupAggregate算子,而不是HashAggregate算子来完成Group By
的计算,这个问题不是本节的重点,结尾处会再来优化这个问题,下面先看看这个缺省
的执行计划的实际执行情况:
从EXPLAIN ANALYZE的输出可以看出,表扫描之后重分布算子就花费了22秒的时间。
接下来对执行计划进行适当的干预,避免出现计算倾斜,设置如下的GUC参数:
SET optimizer_force_multistage_agg TO ON;
此时,执行计划变为:
图形化的执行计划为:
版权所有:Esena(陈淼 ) 编写:陈淼 - 400 -
Greenplum Database 管理员指南 V6.2.1
从执行计划可以看出,扫描完数据之后,先进行了本地AGG操作,这样就避免的计
算倾斜。实际执行情况:
整个SQL的耗时,从52秒下降到了7秒。
最后,将GroupAggregate的问题进行一下优化:
设置如下的GUC参数:
SET optimizer_force_multistage_agg TO ON;
SET optimizer_enable_groupagg TO OFF;
再看一下执行计划:
图形化的执行计划为:
实际执行情况:
版权所有:Esena(陈淼 ) 编写:陈淼 - 401 -
Greenplum Database 管理员指南 V6.2.1
整个SQL的耗时,下降到了0.9秒,这是因为,在大多数情况下GroupAgg的性能
远不如HashAgg的性能,根本原因是Sort的计算复杂度是O(NlnN),而Hash的计算
复杂度为O(N))。
编者无法进行大篇幅的举例说明,毕竟真实生产情况下,计算倾斜的情况比这个例
子要复杂的多,不过,编者希望这个例子能成为一个学习和解决计算倾斜的入门示例。
在官方文档中,还介绍了如何如何通过gpssh工具来查看每个Primary的溢出文
件情况,以此来分析发生倾斜时,哪些Primary因为内存资源的不足而导致大量的产
生溢出文件到磁盘上,实际上,编者认为,直接通过gp_toolkit的几个workfile的
视图就可以很好的发现溢出文件的问题:gp_workfile_entries、
gp_workfile_usage_per_query、gp_workfile_usage_per_segment。
分区
合理的分区,将有助于减少相关查询需要扫描的数据量,也将有助于对数据进行周
期性管理。每个叶子分区,都是一个独立的数据表,在每个Instance上,数据都存储
在独立的数据文件中。分区与分布,是完全不相关的两个概念,分布,是数据在多个
Instance之间分散,分区,在每个Instance看来,数据被拆分存储在多个独立的数
据库表中。如果对于分库分表能够理解的话,分布类似于分库,分区类似于分表。
不过,如果没有任何的分区裁剪,而是做全表查询,则,分区表的性能会低于同样
数据的非分区表,因为需要打开更多的文件,以及对扫描的结果进行合并。这就如同列
存表与行存表,如果要查询所有的字段,列存表的性能会低于同样数据的行存表,因为
需要打开更多的文件,甚至还需要把不同字段的数据重新组织为ROW。
下面是分区的最佳实践:
只对特别大的表进行分区--这是所有条件中必须满足的条件,不满足该条件的任
何表,都不应该进行分区。永远不要对小表进行分区,哪怕它的表结构和应用场景
非常的具有周期性和规律性。
版权所有:Esena(陈淼 ) 编写:陈淼 - 402 -
Greenplum Database 管理员指南 V6.2.1
选择分区字段时,要确保该字段可以用于查询条件,从而可以进行分区消除,以降
低查询扫描的数据量。
只有等值表达式和比较大小的表达式,可以用于分区裁剪,比如这些操作符:=、
<、<=、>、>=和<>。当然,对于ORCA来说,还可能会有动态分区裁剪(Partition
selector算子)。
分区选择,只适用STABLE和IMMUTABLE类型的函数,对VOLATILE类型的函数不
适用,这是因为STABLE和IMMUTABLE类型的函数是事务稳定的,VOLATILE类型
的函数对于任意一次的执行,都具有不确定性,可以参考"在GP中使用函数"章节
获得更多关于函数易变性的解释。
例如,下面这种条件:
date > CURRENT_DATE
这个条件可以使用分区裁剪,因为在整个事务期间,CURRENT_DATE的结果是不
变的,所以,优化器可以提前将其替换为一个常量。但是,如果是下面这种条件:
date > TIMEOFDAY
这个条件,将无法使用分区裁剪,因为对于每条记录来说,TIMEOFDAY的输出都
在变化。如果能使用STABLE和IMMUTABLE类型的函数作为分区字段的过滤条件,
则,应该避免使用VOLATILE类型的函数作为分区字段的过滤条件,需要特别注意
的是,创建函数时,缺省的易变性属性是VOLATILE类型。
如果可以选择范围(range)分区,最好不要选择列表(list)分区。列表分区,每
个分区对应的都是孤立的值,对于只有有限个DISTINT数量的字段,进行分区,
往往没有必要,因为不一定会带来显著的性能提升。
要选择常常会用于条件过滤的字段作为分布键字段。
不要用分布键作为分区字段。一般来说,这两个概念不应该有交集,分布键,一般
是某个业务表的主键,具有很高的唯一性,比如,手机号,身份证号码,客户号等,
而分区字段,一般应该是具有可比较大小和范围的字段,比如,时间,日期等。
不要使用缺省分区。PostgreSQL优化器一定会扫描缺省分区,而且,有缺省分区
的情况下,添加分区必须通过split缺省分区来完成。ORCA在进行分区裁剪时,
会跳过对缺省分区的扫描。
杜绝使用多级分区,多级分区很容易使得表的数量失控,从而导致文件数过度膨胀。
不要过度的曲解分区的功能,分区不是万能膏药。
版权所有:Esena(陈淼 ) 编写:陈淼 - 403 -
Greenplum Database 管理员指南 V6.2.1
虽然GP支持多级子分区,但是,编者衷心奉劝,功能是功能,最佳实践是最佳实
践,如果有可能,应该杜绝使用一级以上的分区,编者在初始化GP集群时,会缺
省将GUC参数gp_max_partition_level设置为1,不允许创建多级分区表。多
级分区,很容易导致很多叶子分区实际上存储的数据量很小甚至是空表,未必带来
性能的提升,反而会为分区维护带来异常的复杂度,最终,可能会把业务的性能搞
的更差,使得情况变得更糟糕。
需要合理控制分区粒度,不要过度零碎的进行分区。每个叶子分区,在每个
Primary上的数据量应该控制在100MB以上,或者记录数在100万条以上。比如集
群有100个Primary,那么可以使用一个通用的简化标准:每个叶子分区的数据量
在1亿条以上。同时,单表,在单个Primary上的记录数低于500万条时,建议不
做分区,即,比如集群有100个Primary,单表记录数在5亿以下时,可以不分区。
应该检查执行计划,是否有分区裁剪,以确定分区是否对查询有帮助。
当需要对列存表进行分区时,每个分区的记录数应该更大,因为列存表是按照每个
字段作为一个单独的数据文件来存储的。整个分区表的数据文件数量为:
文件数量 = Primary数量 × 分区数量 × 字段数量
比如,100个Primary的集群,一张表有100个分区,有100个字段,那么数据文
件的数量就会达到100万个,如果再有多并发INSERT导致AO表文件分裂,最坏的
情况下,文件数将达到1.28亿个,每个Primary上的文件数,最坏的情况下,可
以达到128万个,这些数字都是极其糟糕的。
在对列存表进行分区时,应该控制每个叶子分区,在每个Primary的记录数在
1000万以上。
注意:编者认为,合理的分区对于大表的查询性能提升和数据周期管理都有很大帮助,
所以,应该合理的使用分区表,但是绝对不要过度分区,也不要完全不用分区。
分区和列存的文件数
GP数据库,在软件层面,并未对文件数有任何限制,所以,总的文件数量需要控
制在什么范围,主要取决于主机的配置和文件系统的性能。但是,根据编者的实施经验
来看,如果能将一个Instance的文件数控制在20万以下,将是非常良好的状态,相反
的,如果文件数达到100万,将会有很多问题随之而来,比如,IO性能下降,
gprecoverseg -F的操作耗时过长(与同样容量但文件数较少的情况相比)。
对于一个Instance来说,一个分区表的文件数,会受到分区数量的很大影响,尤
其是列存分区表。比如,一张分区表有400个子分区,如果使用列存,每个字段都需要
版权所有:Esena(陈淼 ) 编写:陈淼 - 404 -
Greenplum Database 管理员指南 V6.2.1
存储到一个单独的文件,如果有100个字段,那么,这样一张分区表,将产生4万个文
件,这对于一个Instance来说,一个表就产生了4万个数据文件,影响极大,如果出
现了并发INSERT导致文件分裂的情况,一个文件最多还会分裂成为128个文件,也就
是说,这样一张有100个字段的400个子分区的表,在最严重的情况下,最多可能会产
生128万个数据文件。
要控制单个Instance的数据文件的数量,从表设计的角度来说,合理控制分区表
和列存的使用,极其重要,另外,就是定期对系统的数据表文件数进行监控,另外,
VACUUM和VACUUM FULL无法降低因为并发INSERT导致的文件数膨胀问题,只有
REORGANIZE可以解决该问题。
索引
通常来说,GP数据库不需要依赖索引来进行分析型场景的性能优化,因为分析型
场景,一般都是对大量数据进行分析,可能是表中的全部数据,或者很大比例的数据,
这种情况下,索引的存在,并不会为数据过滤带来性能提升,甚至说,如果一定要用索
引来进行数据扫描,反而可能会带来严重的性能问题。
由于GP已经是MPP架构,在扫描一张数据表时,所有Primary会并行扫描数据文
件,性能已经非常高,如果全表扫描的性能可以满足业务要求,那么,尽量不要创建索
引,索引的维护也需要很高的代价,包括磁盘空间,IO性能资源和CPU的计算资源。
对于高选择性的查询,可以在相关的字段上创建索引,以提升查询的性能。如果这
种查询很少发生,则创建索引的代价会远远超过带来的收益,所以,应该只为高选择性,
且会多次使用的查询场景,考虑使用索引来提升查询的性能。
应该通过检查执行计划和进行实际的业务测试来确认索引的效果,如果发现索引的
存在并没有带来性能的提升,那么,应该删除该索引。
避免为高频更新的字段创建索引。索引字段的更新一定会导致索引的更新,从而导
致索引的膨胀,严重的甚至导致索引失效。
对于表达式索引,要确保该索引的表达式,能够在查询中经常被使用到,应该通过
检查执行计划和进行实际的业务测试,来确定表达式索引的确会带来性能的提升,否则,
不应该保留这样的索引。
对于条件索引,如果在一个大表上,经常会使用某方面特定范围的条件来过滤很少
的数据,可以考虑建立一个条件索引,这样,将只会在满足条件范围的数据上创建索引。
避免索引的重叠,因为,在同一个字段上创建多个索引,一定会使得索引维护的代
价更高,却未必会带来性能的提升,尤其是不同的索引,开始的字段相同的情况,是完
版权所有:Esena(陈淼 ) 编写:陈淼 - 405 -
Greenplum Database 管理员指南 V6.2.1
全多余的。
在返回少量结果的场景下,索引同样可以改善压缩 AO 表上查询的性能,当情况合
适时优化器会把索引作为获取数据的选择,而不是一味的全表扫描。对于压缩数据来说,
索引访问数据时只解压需要的记录而不是全表解压(最小单元的压缩块是要解压的)。
应该为高选择性字段创建 B-tree 索引,而不是 Bitmap 索引
对于加载数据量较大的场景,应该考虑删除索引后再加载数据,在完成数据加载后
重建索引。这个比较难找到一个确切的界限,当需要加载的数据量不是很大,也不是很
小时,重建索引未必会比直接带索引加载更快。
对于经常需要被更新的字段,不应该使用 Bitmap 索引。编者认为,实际上 Bitmap
索引,在 GP 数据库中,几乎没有存在的价值。
对于分区表,尽量不使用索引,如果必须使用索引,一定要与分区字段不同。
总之,不要过度的曲解索引的功能,索引不是万能膏药,在该用的时候用,不该用
的时候不要用,无效索引,是对整个集群的各种资源的极大浪费。
更多关于使用索引的说明,可以参见"在GP中使用索引"章节。
资源组管理内存等资源
资源组,是一种新的资源管理方式,相比于资源队列,可以精确的管理内存、CPU
和并发事务数量,所以,未来,应该逐渐转向使用资源组来取代资源队列,对GP数据
库集群,进行资源管理。
GP 数据库的内存配置
理论上来说,内存是越多越好,但实际情况是,不可能总是增加内存,所以,有必
要对内存的使用进行必要的管理,以尽可能的避免出现内存不足的情况。
使用资源组来管理GP数据库资源时,以下是操作系统和GP数据库,内存设置非常
重要的因素:
vm.overcommit_memory
版权所有:Esena(陈淼 ) 编写:陈淼 - 406 -
Greenplum Database 管理员指南 V6.2.1
这是非常重要的Linux Kernel参数,在/etc/sysctl.conf配置文件中设置,
该参数的值决定了操作系统如何对内存进行分配和管理。GP数据库要求
vm.overcommit_memory必须设置为2。对于overcommit的三种选择0、1、2
对应了不同的行为,0,允许适度的超限申请内存,1,允许无节制的超限申请内
存,2,禁止超限申请内存。为什么GP要求配置为2呢,因为,对于0和1两种情况,
都有可能会触发oom-killer,一旦触发该行为,将无法确保数据库主服务进程一
定不会被选中成为被kill的进程,那将是十分危险的。
vm.overcommit_ratio
这是Linux Kernel参数,在/etc/sysctl.conf配置文件中设置,决定了操作
系统可用内存的计算结果,编者建议vm.overcommit_ratio的值设置为95。不
应该通过该参数来实际控制GP数据库的内存使用量,而是应该通过GP数据库自身
的GUC参数gp_resource_group_memory_limit的值来决定数据库的资源组
可用内存总量,将vm.overcommit_ratio的值设置为95,只是为了使得操作系
统的可用内存的计算结果足够大,但不是真的按照这个结果来计算GP的GUC参数
gp_resource_group_memory_limit的值,建议根据实际情况调整GUC参数
gp_resource_group_memory_limit的值。
gp_resource_group_memory_limit
资源组可用的内存,占操作系统可用内存的百分比,缺省为0.7(70%)。这里有个
问题,在开启资源组的情况下,内存限制不再受gp_vmem_protect_limit的控
制,而是受gp_resource_group_memory_limit的控制,也就是说,使用资源
队列时,gp_vmem_protect_limit控制着单个Instance的总内存使用量,使
用资源组时,gp_resource_group_memory_limit控制着单个Instance的总
内存使用量。注意,尤其在开启资源组时,SWAP的配置显得尤为重要,必须配置
为和物理内存固定的比值。
hugepage
要禁用hugepage特性。主机的内存分配的控制,应该由GP数据库来统一管理。
gp_workfile_limit_files_per_query
可以通过控制GUC参数gp_workfile_limit_files_per_query的值来控制
一个查询在一个Primary上的溢出文件的个数,如果设置为0,就意味着对溢出文
件的数量不做任何的限制,不过,限制溢出文件的数量,可以防止劣质的查询对系
统造成破坏性影响。编者建议,不要修改这个参数,或者,如果要改,就改小一些,
以阻止更多的劣质查询对系统的影响。
gp_workfile_compression
版权所有:Esena(陈淼 ) 编写:陈淼 - 407 -
Greenplum Database 管理员指南 V6.2.1
GUC参数gp_workfile_compression用于控制溢出文件是否进行压缩存储,在
6之前的版本,类似的参数为gp_workfile_compress_algorithm,一般配置
为zlib,在6版本中,gp_workfile_compression是一个布尔型的参数,一般
建议配置为on。缺省情况下,溢出文件是不压缩的,编者建议压缩。
memory_spill_ratio
开启资源组的情况下(通过 gpconfig 配置 gp_resource_manager 为 group
来开启),如果 GUC 参数(或者资源组的属性)memory_spill_ratio 的值不为 0
的情况下,语句的内存分配由资源组根据内存配额,最大活动事务数和
memory_spill_ratio 参数的值来决定,详情可以参见"算子内存配额"章节。
statement_mem
在开启资源组,并且 memory_spill_ratio 为非零时,语句的内存分配根据内
存配额,最大活动事务数和 memory_spill_ratio 参数的值来决定。否则,由
statement_mem 决定,计算方法参见"算子内存配额"章节。也就是说,如果没
有开启资源组,由 statement_mem 决定,如果开启了资源组,而
memory_spill_ratio 为 0,仍由 statement_mem 决定。
编者不喜欢通过 memory_spill_ratio 的方式来控制内存,如果所有的事务的
内存分配都通过这种方式来控制,那么,相当于总的内存量已经按照事先划分的资源组
和并发事务数量进行了定量分割,但是,实际的使用中,是做不到所有时间都有这么多
的事务在运行,而当某个任务需要更多的内存,却无法获取到,会造成内存资源的极大
浪费。编者还是更倾向于通过 statement_mem 来控制内存的分配,允许有交叉重叠,
允许总量超过内存总数,但不是真的超过,而是动态总的使用量保持小于内存总量,这
是一种相对安全的控制,而不是绝对安全的控制。
在使用资源组时关于内存的考虑
资源组的可用内存,会受到一些参数和设置的限制,物理内存的尺寸,SWAP的尺
寸,vm.overcommit_ratio和gp_resource_group_memory_limit的设置。要
确保GP数据库能够充分利用每个主机的内存资源,可能需要调整这些参数:
1. 操作系统的SWAP尺寸。
2. Linux Kernel参数vm.overcommit_ratio。
3. 资源组GUC参数gp_resource_group_memory_limit。
在使用资源组时,资源组的可用内存总量不再受gp_vmem_protect_limit的控
版权所有:Esena(陈淼 ) 编写:陈淼 - 408 -
Greenplum Database 管理员指南 V6.2.1
制,而是与主机的物理内存总量和这3个参数有直接关系,但是,编者认为,需要确保
资源组的可用内存总量,不要超过物理内存总量。对于一个Primary来说,所有资源
组可用内存的总量为:
int(
(RAM × (vm.overcommit_ratio ÷ 100) + SWAP)
× gp_resource_group_memory_limit
÷ num_of_active_primary
)
配置资源组
GP数据库的资源组,为资源管理和工作负载管理,提供了更精确的控制。在配置
资源组时,需要考虑以下一些原则:
具有SUPERUSER权限的角色,缺省会在admin_group资源组下运行。这是需要特
别注意的问题,因为admin_group资源组的缺省最大活跃事务数量是10,很多时
候,这个值可能无法满足,所以,应该合理的安排SUPERUSER的使用,或者增加
admin_group资源组的最大活跃事务数量。
为每个非SUPSERUSER角色分配一个合适的资源组,否则,该角色将在
default_group资源组下运行。应该为不同类型的角色分配合适的资源组,这样
便于对资源进行更精确的管理和控制。
通过资源组的CONCURRENCY属性来控制一个资源组上,所有角色的最大活跃事务
数量。
GP数据库将未配额给资源组的内存(100减去所有资源组的MEMORY_LIMIT属性
值),留作全局可共享内存。这部分内存对于所有的事务来说,是先到先得。
可以根据资源组的负载情况,动态的调整资源组的属性,以及时的适应工作负载的
变化。对资源组的属性的修改,是及时生效的,数据库会动态的进行资源评估。
可以使用gp_toolkit模式中关于资源组的视图来监控资源组的使用情况。详情可
以参考"监控资源组状态"章节。
还可以通过GPCC的图形界面来实现资源组的创建和管理配置,以及动态修改运行
中的事务的所属资源组。
版权所有:Esena(陈淼 ) 编写:陈淼 - 409 -
Greenplum Database 管理员指南 V6.2.1
低内存消耗型的查询
官方文档上说,对于低内存消耗型的查询来说,设置如下的参数可以提升查询的性
能,编者觉得,有待验证,至少,编者认为,这种操作可能没有特别显著的性能提升。
=# SET memory_spill_ratio=0;
=# SET statement_mem='10MB';
通过设置memory_spill_ratio为0(实际上缺省值也是0,资源组的该属性缺省
值也是0),来关闭资源组的内存管理模式,内存分配以statement_mem参数的设置为
准。不过,虽然说对于低内存消耗的查询来说,设置较低的内存,有可能提升性能,编
者理解,应该也只是针对交易型的场景,然而,编者通过测试,没有发现这个现象。
命令工具与 admin_group 的 CONCURRENCY 属性
GP数据库为SUPERUSER配置的缺省资源组是admin_group,admin_group缺省
的CONCURRENCY属性是10,也就是说,缺省情况下,在启用资源组时,SUPERUSER
执行事务的最大并发是10,超过10个并发事务,也需要排队,注意,在启用资源组的
情况下,SUPERUSER没有特殊待遇,和普通角色一样,都要受到资源组的资源限制。
有些数据库命令可能会运行较多的并发数,比如gpbackup命令的--jobs,比如
analyzedb命令的-p参数。所以,对于这些情况,可能需要临时增加admin_group
资源组的内存和CONCURRENCY的属性值,或者根据日常执行这些命令的情况,适当的
永久增加admin_group资源组的内存和CONCURRENCY的属性值,编者建议,应该适
当的永久增加admin_group资源组的CONCURRENCY属性值。
资源队列管理内存等资源
资源队列是GP数据库一直在使用的资源管理方式,虽然有很多不足,但已经伴随
了GP这个产品很多年,在并发控制和内存管理方面还是有着很重要的作用。资源组是
一种全新的资源管理方式,在内存控制,CPU压制,和并发事务控制方面都有了很大的
增强,所以,未来,应该逐渐转向使用资源组来取代资源队列。
版权所有:Esena(陈淼 ) 编写:陈淼 - 410 -
Greenplum Database 管理员指南 V6.2.1
在GP数据库中,内存管理对性能的影响很大,缺省的内存设置,已经可以满足大
多数的场景,所以,在搞清楚内存管理机制之前,最好不要修改缺省的内存管理设置。
也就是说,缺省使用资源队列来管理内存,如果资源队列可以满足要求,或者还没有理
解资源组的内存管理机制,不应该马上修改为资源组的方式。
解决内存不足的报错
内存不足的报错是有分类的,比如下面这两种,属于gp_vmem_protect_limit
耗尽的报错:
ERROR: Out of memory
(seg0 slice3 192.168.137.66:40000 pid=17836)
DETAIL: VM Protect failed to allocate 33554488 bytes, 31 MB available
这种属于 gp_vmem_protect_limit 剩余可用内存已经无法满足内存分配的需求。
ERROR: Canceling query because of high VMEM usage. Used: 78MB, available
8MB, red zone: 90MB
这种属于所需内存达到了gp_vmem_protect_limit的红线(90%),语句被终止。
注意:上述两种情况,都是属于gp_vmem_protect_limit参数,设置的限制用超了,
如果gp_vmem_protect_limit参数是按照物理内存的0.9倍为基准来配置的,那么,
就不要在gp_vmem_protect_limit参数上动脑筋了,这个参数不能设置过大,设置
过大,就会遭遇接下来要说的系统OOM报错了,剩下能做的事情就是,试试如何降低内
存的使用需求,或者增加物理内存,也不要试图用SWAP来冒充物理内存,因为性能差
了几个数量级。
下面这种,属于操作系统报出的OOM错误:
ERROR: Out of memory
(seg0 slice3 192.168.137.66:40000 pid=23729)
VM protect failed to allocate 33554488 bytes from system, VM Protect 1269
MB available
这种情况,一般是gp_vmem_protect_limit的设置超出了操作系统的可用内存
上限。也就是说,gp_vmem_protect_limit的限制还没有到,却已经无法从操作系
统获取内存,说明gp_vmem_protect_limit参数的设置太大了。
GP数据库出现内存不足的一些常见原因有:
可用的系统内存不足。就是内存配置的太低了,现在主流的生产机器的配置,单机
一般物理内存至少达到256GB。内存低,还想多并发执行,大数据量的复杂任务,
版权所有:Esena(陈淼 ) 编写:陈淼 - 411 -
Greenplum Database 管理员指南 V6.2.1
那是不可能的,违背自然规律了。
内存相关的参数配置不正确。gp_vmem_protect_limit参数的配置要符合系统
的内存资源现状,既不能太小,也不能太大,太小,内存资源利用不足,太大,容
易出现操作系统报OOM错误。编者建议按照物理内存的0.9倍为基准来配置
gp_vmem_protect_limit参数的值。
数据倾斜。
计算倾斜。
解决内存不足报错的一些方法:
SQL调优,以减少内存的使用量。虽然很多时候会被技术人员抗拒,但是,在其他
优化调整已经没招的情况下,如果必须在SQL优化和增加硬件之间选择,没有一个
决策者会优先选择增加硬件,因为硬件没有终点,但SQL调优,往往可能会节省一
大笔的硬件投资,SQL写的烂,还硬要把锅甩给硬件和数据库,自己是不是有点尴
尬。任何数据库都需要SQL调优,只有不懂数据库的技术人员才会持有不同意见,
SQL设计的初衷,是给专业计算机技术人员使用的。
确认gp_vmem_protect_limit参数的配置是否合理。编者建议按照物理内存的
0.9倍为基准来配置gp_vmem_protect_limit参数的值。
对资源队列,设置内存使用量的限制,从而限制资源队列中的查询语句使用的内存
量。过低的内存分配,会影响任务的处理性能,应该在并发数控制方面多考虑。
降低业务的并发数。系统最终追求的目标是,单位时间内完成的任务数量,过高的
并发只会导致资源的严重争抢,从而导致单位时间内完成了更少的任务数量。
在会话级别,降低statement_mem参数,以减少内存的使用量。编者认为,这一
点比较难做到,尤其是大规模的复杂系统,出现内存不足之后,再考虑从会话级别
降低statement_mem参数的值,比较困难。
在数据库级别,降低statement_mem参数的值。这个很容易实现,直接通过ALTER
DATABASE命令即可修改数据库级别的参数值。
降低GP集群中每个计算主机上Primary的数量。这个也是难以操作,因为需要重
建集群,几乎不可能做得到。
增加物理内存。这个虽然不然容易,但是,如果物理内存的确太少,而其他方法又
难以完全实现最终目标,还是应该考虑增加物理内存,物理内存太低的话,很难有
什么办法,既不降低计算性能,又不降低并发处理能力,还能避免内存不足的报错,
这违背自然规律了。
版权所有:Esena(陈淼 ) 编写:陈淼 - 412 -
Greenplum Database 管理员指南 V6.2.1
集群扩容增加计算主机的数量,不会从本质上缓解内存不足的问题,因为每个查询
消耗的内存量,受到statement_mem参数的控制,不过,如果增加了计算主机的数量,
可以降低每个计算主机的数据量的话,可以降低statement_mem参数的值,这样可以
缓解内存不足问题,或者,在增加计算主机数量的时候,减少每个计算主机的Primary
的个数,从而可以增加gp_vmem_protect_limit的值,也可以缓解内存不足的问题。
低内存消耗型的查询
官方文档上说,对于低内存消耗型的查询来说,设置如下的参数可以提升查询的性
能,编者觉得,有待验证,至少,编者认为,这种操作可能没有特别显著的性能提升。
=# SET statement_mem='2MB';
虽然说对于低内存消耗的查询来说,设置较低的内存,有可能提升性能,编者理解,
应该也只是针对交易型的场景,然而,编者通过测试,没有发现这个现象。
为 GP 数据库进行内存配置
如果能够深入理解GP的内存管理方法,绝大部分的内存不足的报错,是可以避免
的。在增加物理内存比较困难的时候,通过正确的进行内存相关的参数配置,结合资源
队列的控制,可以有效缓解和防止出现内存不足的报错。
还需要注意一点,当发生故障切换时,Mirror会切换为Primary,并承担处理任
务,同样需要消耗内存,所以,在进行内存规划时,也需要考虑到这个因素。但是,编
者认为,绝大部分时间,Mirror在处于Mirror状态时,是不需要消耗内存的,所以,
不应该将物理内存为可能发生切换的Mirror做预留,而是要依赖SWAP来做保障,这也
是编者一直强调SWAP的尺寸要与Mirror策略保持一致的原因,一般的通用方案是,
SWAP的尺寸与RAM相等。因此,在配置内存参数时,将vm.overcommit_ratio设置
为95,确保系统可用内存的总量接近理论最大值,而在配置
gp_vmem_protect_limit时,只考虑物理内存和Primary的关系,剩余的可用内存
其实都是SWAP提供的,当Mirror切换为Primary时,有足够的保障,同时,并不是
任何时候,内存的使用量都是很高的,SWAP只是一种保障。
下面是操作系统和GP数据库的内存配置方面的建议:
要禁用hugepage特性。主机的内存分配的控制,应该由GP数据库来统一管理。
版权所有:Esena(陈淼 ) 编写:陈淼 - 413 -
Greenplum Database 管理员指南 V6.2.1
vm.overcommit_memory
这是非常重要的Linux Kernel参数,在/etc/sysctl.conf配置文件中设置,
该设置决定了操作系统如何对待进行内存分配的管理。GP数据库要求
vm.overcommit_memory必须设置为2。对于overcommit的三种选择0、1、2
对应了不同的行为,0,允许适度的超限申请内存,1,允许无节制的超限申请内
存,2,禁止超限申请内存。为什么GP要求配置为2呢,因为,对于0和1两种情况,
都有可能会触发oom-killer,一旦触发该行为,将无法确保数据库主服务进程一
定不会被选中成为被kill的进程,那将是十分危险的。
vm.overcommit_ratio
这是Linux Kernel参数,在/etc/sysctl.conf配置文件中设置,决定了操作
系统可用内存的计算结果,编者建议vm.overcommit_ratio的值设置为95。不
应该通过该参数来实际控制GP数据库的内存使用量,在开启资源队列的情况下,
应该通过GP数据库自身的GUC参数gp_vmem_protect_limit的值来决定数据
库的内存使用量,将vm.overcommit_ratio的值设置为95,只是为了使得操作
系统的可用内存的计算结果足够大,但不是真的按照这个结果来计算GP的GUC参数
gp_vmem_protect_limit的值。
gp_vmem_protect_limit
gp_vmem_protect_limit参数用于限制,在开启资源队列的情况下,一个
Instance的最大使用内存的总量,如果设置过大,将会导致出现操作系统内存不
足的报错,设置过小,又会导致内存利用不足。编者建议按照物理内存的0.9倍为
基准来配置gp_vmem_protect_limit参数的值。
runaway_detector_activation_percent
在4.3.4版本开始引入的新GUC参数,用于控制查询,以防止出现内存不足的情况。
runaway_detector_activation_percent参数控制的是,在
gp_vmem_protect_limit使用到多少百分比时,触发查询终止。缺省值为90,
即,90%,当gp_vmem_protect_limit使用量达到90%,数据库将开始终止查
询,从内存消耗量最大的查询开始终止,一直到gp_vmem_protect_limit的使
用量低于指定的百分比为止。
一般来说,不需要修改此参数,如果出现了内存不足的报错,应该寻求提升内存配
置,或者降低内存使用量。
statement_mem
编者认为,statement_mem与gp_vmem_protect_limit参数和最大并发查询
的数量这两个参数之间,并没有严格的等式关系,并不是说statement_mem的值
一定不能超过[(gp_vmem_protect_limit × 0.9) ÷ 最大并发查询的数量]
版权所有:Esena(陈淼 ) 编写:陈淼 - 414 -
Greenplum Database 管理员指南 V6.2.1
计算的结果,因为,很多时候,内存的真实使用量并不大。根据编者的经验,可以
通过持续多日的对系统资源进行统计,确定系统的最高活跃内存百分比,比如,当
statement_mem使用的是缺省的125MB的情况下,统计发现,系统的最高活跃内
存百分比为30%,那么,将statement_mem设置为125MB的3倍是安全的,用真
实的数据来推导出一个合理的值,总是比通过公式计算出的结果更实用。
gp_workfile_limit_files_per_query
可以通过控制GUC参数gp_workfile_limit_files_per_query的值来控制
一个查询在一个Primary上的溢出文件的个数,如果设置为0,就意味着对溢出文
件的数量不做任何的限制,不过,限制溢出文件的数量,可以防止劣质的查询对系
统造成破坏性影响。编者建议,不要修改这个参数,或者,如果要改,就改小一些,
以阻止更多的劣质查询对系统的影响。
gp_workfile_compression
GUC参数gp_workfile_compression用于控制溢出文件是否进行压缩存储,在
6之前的版本,类似的参数为gp_workfile_compress_algorithm,一般配置
为zlib,在6版本中,gp_workfile_compression是一个布尔型的参数,一般
建议配置为on。缺省情况下,溢出文件是不压缩的。
配置资源队列
资源队列,对GP数据库的资源管理和控制提供了保障,资源队列最常用的功能是,
控制活跃查询的数量,还可以用于控制查询语句的内存使用量。在开启资源队列的情况
下,当一个查询被提交到数据库,其资源会受到所在资源队列的限制,数据库将根据资
源队列的资源情况来决定是否执行SQL,马上执行还是排队,等等。
所有的角色都应该设置合理的资源队列。
每个角色都与一个资源队列相关连,在开启资源队列的情况下,任何查询都需要经
过资源队列才能得到执行(SUPERUSER不受资源队列的限制),如果没有为角色指
定资源队列,缺省将分配到pg_default资源队列。
不用使用gpadmin用户或者具有SUPERUSER权限的角色执行业务查询。
SUPERUSER是完全不受资源队列限制的,所以,SUPERUSER执行的业务查询,总
是直接被执行,这将不利于资源的管理和控制。
使用ACTIVE_STATEMENTS属性来控制资源队列中,所有角色同时执行查询语句
的数量。
版权所有:Esena(陈淼 ) 编写:陈淼 - 415 -
Greenplum Database 管理员指南 V6.2.1
使用MEMORY_LIMIT属性来控制资源队列中所有查询的总的内存使用量。一般结
合ACTIVE_STATEMENTS属性来使用,建议不要结合MAX_COST来使用。当与
ACTIVE_STATEMENTS结合使用时,缺省每个语句获得的内存为:MEMORY_LIMIT
/ ACTIVE_STATEMENTS。当与MAX_COST结合使用时,缺省的内存分配为:
MEMORY_LIMIT * (query_cost / MAX_COST)。推荐与ACTIVE_STATEMENTS
结合使用而不是与MAX_COST结合使用,因为cost的评估很多时候会严重失准,
这样将会严重影响内存分配的合理性。
关于资源队列的优先级设置,几乎没有实际意义。使用资源队列主要还是用于控制
并发查询的数量。
使用gp_toolkit模式中,资源队列相关的视图来查看资源队列的状态。详情请参
见"检查资源队列状态"章节。
编者认为,资源队列最重要的作用是控制并发查询的数量,当然,有时候,
MIN_COST 属性也非常好用,可以将一些小查询直接放行,提升资源控制的灵活性。
版权所有:Esena(陈淼 ) 编写:陈淼 - 416 -
|