Greenplum Database (V6.2.1) - 8

 

  Index      Manuals     Greenplum Database (V6.2.1)

 

Search            copyright infringement  

 

   

 

   

 

Content      ..     6      7      8      9     ..

 

 

 

Greenplum Database (V6.2.1) - 8

 

 

Greenplum Database 管理员指南 V6.2.1
比如安装GP数据库软件建立新旧主机之间的ssh互信执行性能评估测试
这些准备工作全部完成并且确认性能测试结果符合扩容条件后即可开始下一步的数据
库扩容操作。
对于性能测试首先应该在用于扩容的新主机上进行测试在确认新主机的性能测
试符合预期之后再计划一个业务空闲的时间窗口或者完全没有业务的时间窗口
所有主机进行性能测试因为用户访问会影响测试结果的真实性不利于对整体集群
的情况进行准确的评估。
在完成性能测试之后如果性能测试的结果不理想需要对集群的配置情况进行评
之后再排查可能导致性能不符合预期的原因如果修改了某方面的配置则需要重
新进行性能测试直到性能测试的结果符合预期为止。
注意性能测试非常重要其反应的是主机的基本性能指标是未来集群运行性能的基
础参考。编者提醒主机的操作系统安装和Raid配置以及操作系统参数的修改等
一定要严格按照GP数据库安装要求逐项落实毕竟性能测试不是真实的生产压力
可能发现所有的潜在问题比如Raid策略和参数设置连续IO读写测试与真实的多并
IO请求完全不同如有疏漏等到真正开始数据重分布并承载业务压力时再发现
就迟了势必会拖长扩容的时间影响业务的正常恢复。
将新的主机加入 ssh 互信
几乎所有的GP管理命令都依赖ssh互信所以首先要完成的是所有新主机与现
有主机之间完成ssh互信。不管是新建还是扩容gpadmin用户的互信是必须要建的
否则数据库一定无法正常运行虽然SQL命令一般不依赖ssh互信但是应该不可
能有哪个集群永远不需要使用管理命令。
为了便于进行多机安装和配置GP要求root用户也要建立ssh互信使用编者的
自动安装部署脚本不需要建立root用户的ssh互信只需要运行安装的用户有sudo
权限即可ssh互信只会在gpadmin用户之间建立。在有些环境甚至不允许使用
root用户来登录操作系统所以这时候的手动安装可能会比较麻烦一些。编者需要
提醒的是无论如何必须要有sudo权限否则无法正常的安装GP数据库也无法
正常的进行扩容前的准备工作。
GP集群的主机名称按照惯例采用sdwN的形式其中sdw是前缀N是数字后
如果需要可以将前缀改为任何Alpha字符串建议不要使用任何的特殊字符或者
大写字符建议使用容易记住和辨识的前缀这对于后续的使用和运维是有帮助的
别拗口的名称并不利于交流和书写记忆。另外编者提醒数字后缀应该采用定长数
不足的位置为使用0补位因为比如在GPCCgpinitsystem主机名
是按照字符串进行排序的sdw2会排在sdw1之后sdw1x则会排在sdw2之前。
版权所有Esena(陈淼 ) 编写陈淼 - 350 -
Greenplum Database 管理员指南 V6.2.1
对于多子网端口的主机来说按照惯例一般采用在主机名之后添加-M的形式
来命名子网端口比如主机名为sdw001不同的子网端口可以是sdw001-1
sdw001-2等。建议不要使用其他特殊字符(比如下划线)而是遵守GP数据库的惯例。
建立 root 用户的 ssh 互信
1. 将集群中所有主机的主机名和子网端口在一个主机名文件中列出每行一个主机
名或者子网端口名称不要有其他无关字符编者还会把主机名和子网端口名称对
应的IP地址也一并列出确保所有可能用得到的访问地址都建立了ssh互信。另
对于用于扩容的新主机将这些新主机的主机名在另一个单独的文件中列出
因为后续的一些只针对新主机的操作会用到该文件。
例如Master的主机名为mdw001Standby主机名为mdw002现有两个计算节
点主机为sdw001sdw002新增2台主机的主机名为sdw003sdw004
个计算节点主机对应2个子网端口。例如all_hosts的内容如下
172.28.4.250
mdw01
172.28.4.251
mdw02
172.28.4.1
sdw01
sdw01-1
172.28.8.1
sdw01-2
172.28.4.2
sdw02
sdw02-1
172.28.8.2
sdw02-2
172.28.4.3
sdw03
sdw03-1
172.28.8.1
sdw03-2
172.28.4.4
sdw04
sdw04-1
172.28.8.4
sdw04-2
版权所有Esena(陈淼 ) 编写陈淼 - 351 -
Greenplum Database 管理员指南 V6.2.1
new_hosts的内容如下
sdw003
sdw004
2. 使用root用户登录Master主机执行如下命令
$ su -
# source /usr/local/greenplum-db/greenplum_path.sh
3. 对于6版本需要先建立Master与每个主机的ssh互信。例如
# ssh-copy-id -i ~/.ssh/id_rsa.pub root@sdw03
4. 使用gpssh-exkeys命令建立全局互信
# gpssh-exkeys -f all_hosts
对于6之前的版本不需要上一步操作可以直接执行gpssh-exkeys命令并根据提
示输入密码
***Enter password for root@hostname: <root_password>
创建 gpadmin 用户
1. 使用之前创建的new_hosts文件在所有新主机上创建gpadmin用户例如
# gpssh -f new_hosts -e 'groupadd -r -g 300 gpadmin'
# gpssh -f new_hosts -e 'useradd -r -m -g gpadmin -u 300 gpadmin'
2. gpadmin用户设置密码
# gpssh -f new_hosts -e 'echo gpadmin | passwd gpadmin --stdin'
3. 确认gpadmin用户已经正确创建
# gpssh -f all_hosts -e 'ls -l /home|grep gpadmin'
版权所有Esena(陈淼 ) 编写陈淼 - 352 -
Greenplum Database 管理员指南 V6.2.1
# gpssh -f all_hosts -e 'id gpadmin'
注意预期的结果是所有主机上gpadmin用户都有相同的home目录所有主机上
gpadmin用户的id命令输出完全一致。
建立 gpadmin 用户的 ssh 互信
1. 使用gpadmin用户登录Master主机对于6版本需要先建立Master与每个主机
ssh互信。例如
# ssh-copy-id -i ~/.ssh/id_rsa.pub gpadmin@sdw03
2. 使用gpssh-exkeys命令建立全局互信
# gpssh-exkeys -f all_hosts
对于6之前的版本不需要上一步操作可以直接执行gpssh-exkeys命令并根据提
示输入密码
***Enter password for gpadmin@hostname: <gpadmin_password>
检查磁盘 IO 性能和网络性能
通过执行gpcheckperf命令来对新主机进行性能测试包括磁盘的性能测试和网
络性能测试详情可参考"系统性能检查"章节。例如进行磁盘性能测试
$ gpcheckperf -r d -f new_hosts -d /data1 -d /data2 -D -V
缺省的测试尺寸可能会很大所以请按照"系统性能检查"章节的建议逐渐加大
尺寸测试该测试可能会耗时较久。这里不再详细介绍如何进行性能测试"系统性能
检查"章节已经介绍的比较详细。需要注意的是在对新主机完成全部的性能测试
对结果进行评估确认新主机性能满足扩容要求之前不能贸然进入下一步扩容操作。
版权所有Esena(陈淼 ) 编写陈淼 - 353 -
Greenplum Database 管理员指南 V6.2.1
新旧主机一起做性能测试
在开始正式初始化新的Instance之前有必要做一个整体的性能测试以评估新
主机和现有主机的整体性能基准至少要确保新主机的性能不能低于现有主机的性能。
如果有可能尽量进行离线测试即停掉现有的GP数据库集群的服务然后进行整体
的性能测试如果无法满足离线的要求也要尽可能做到在无作业时间窗口来完成整体
的性能测试避免数据库任务对测试结果产生影响。具体测试方法请参考"系统性能
检查"章节。磁盘的IO性能与已使用容量的百分比有关尤其是使用百分比达到甚至超
70%性能下降会非常严重这种情况下新主机与现有主机之间的磁盘性能对比
不能只是简单看测试结果还要考虑使用容量导致的性能下降因为新主机的IO
能也会随着使用容量的上升而下降如果有可能应该用新主机的测试结果与现有主
机第一次上线前的性能测试结果做对比。
初始化新 Instance
通过执行gpexpand命令来完成新Instance的初始化操作。总体上来说需要分
三个阶段来运行gpexpand命令。第一阶段通过运行gpexpand命令生成扩容配置
文件一般来说这个阶段只需要运行一次gpexpand命令。第二阶段通过运行
gpexpand命令并指定扩容配置文件gpexpand命令会创建新的Instance并更
新系统表信息生成包含用于数据重分布的信息的gpexpand模式。第三阶段通过运
gpexpand命令来完成数据的重分布这一阶段可能会多次运行gpexpand命令
数据重分布过程是可以中断并继续运行的所以允许管理员灵活的安排数据重分布的
时间直至所有数据表完成数据重分布。
生成扩展配置文件
gpexpand命令需要一个配置文件来确定需要在哪些主机以什么样的方式
建哪些新的Instance这个文件需要通过-i参数来提供。在GP数据库的Master主机
上第一次执行gpexpand命令而且没有指定-i参数命令会进入一个交互界面以获
取必要的信息然后自动生成一个扩容配置文件。
在交互式界面需要提供新增的主机名或者通过gpexpand命令的-f参数提供
一个主机名列表文件如果指定了-f参数只是不会再提示输入主机名而其他信息
仍然需要交互式确认。当然如果可以自行生成扩容配置文件这一步可以跳过。
版权所有Esena(陈淼 ) 编写陈淼 - 354 -
Greenplum Database 管理员指南 V6.2.1
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 运行gpexpand命令。命令启动并进入交互界面提示输入信息以确定如何进行
扩容操作并提示退出还是继续。
3. 比如不带任何参数的执行gpexpand命令将会是如下形式的交互过程
Would you like to initiate a new System Expansion Yy|Nn (default=N):
> y
Enter a comma separated list of new hosts you want
to add to your array. Do not include interface hostnames.
**Enter a blank line to only add segments to existing hosts**[]:
> sdw002
How many new primary segments per host do you want to add? (default=0):
>
Generating configuration file
Input configuration file was written to
'gpexpand_inputfile_20200817_225256'.
Please review the file and make sure that it is correct then re-run
with: gpexpand -i gpexpand_inputfile_20200817_225256
[INFO]:-Exiting...
4. 首先会询问是否要进行一个扩容操作输入[y]以继续。
5. 如果没有通过-f参数来指定一个扩容主机名清单文件则会要求输入主机名
有多个主机名时使用英文逗号[,]分隔不要输入子网端口的名称。例如
**Enter a blank line to only add segments to existing hosts**[]:
> sdw002,sdw003,sdw004
如果只是要为现有集群中计算节点主机增加Primary的数量这一步不需要输
入任何内容直接按回车继续即可。
6. 如果现有集群有Mirror则会提示选择一个Mirror策略可选项有spread
group缺省如果不选择Mirror策略为group
7. 询问希望为现有集群的每个计算节点主机增加几个Primary缺省为0
增加现有计算节点主机上的Primary数量。新扩容主机上Primary的数量会保持
与现有主机上Primary的数量一致。所以假如现有每个计算节点主机上有6
版权所有Esena(陈淼 ) 编写陈淼 - 355 -
Greenplum Database 管理员指南 V6.2.1
Primary如果不输入或者输入0新扩容主机上Primary的数量也会是6
如果输入数字2扩容之后所有计算节点主机上都有8Primary
How many new primary segments per host do you want to add? (default=0):
>
8. 对于6之前的版本还会询问Primary的目录位置这样生成的扩容配置文件中
将会生成以输入的路径为参考路径的Primary工作目录不要输入具体的工作目
录的名称gpexpand命令会在指定的目录下自动生成数据库的工作子目录。
例如现有的数据库工作目录为
/data/primary/gpseg0
/data/primary/gpseg1
为新扩容Primary指定的路径应该是这样
/data/primary
/data/primary
gpexpand会自动在/data/primary下创建gpseg2gpseg3子目录。
9. 对于6之前的版本如果有Mirror会询问Mirror的目录位置这样生成的扩
容配置文件中将会生成以输入的路径为参考路径的Mirror工作目录不要输入
具体的工作目录的名称gpexpand命令会在指定的目录下自动生成数据库的工作
子目录。
例如现有的数据库工作目录为
/data/mirror/gpseg0
/data/mirror/gpseg1
为新扩容Mirror指定的路径应该是这样
/data/mirror
/data/mirror
gpexpand会自动在/data/mirror下创建gpseg2gpseg3子目录。
在上述步骤中需要输入的目录在新扩容的主机上必须已经存在否则后续的扩
容操作会报错说目录不存在这些目录gpadmin用户要有创建子目录的权限。在所
有信息收集完成后gpexpand命令会在当前路径生成一个库容配置文件。例如
gpexpand_inputfile_20200817_225256
版权所有Esena(陈淼 ) 编写陈淼 - 356 -
Greenplum Database 管理员指南 V6.2.1
扩容配置文件的格式
使用交互式界面生成扩容配置文件可以满足一般的需求如果对Mirror策略有
特殊需求则需要对扩容配置文件进行自定义。
GP6版本的扩容配置文件的格式是这样的
hostname|address|port|datadir|dbid|content|preferred_role
例如
sdw003|sdw003-1|40000|/data/primary/gpseg4|6|4|p
sdw003|sdw003-2|40001|/data/primary/gpseg5|7|5|p
sdw004|sdw004-2|50000|/data/mirror/gpseg4|8|4|m
sdw004|sdw004-1|50001|/data/mirror/gpseg5|9|5|m
对于每一行记录实际上对应的是一个即将新初始化的扩容Instance的信息
不同属性的含义如下
属性
有效值
描述
hostname
主机名
生成扩容配置文件时不会检查主机名是否存在。
address
网络端口名称
可以是同一个主机名的不同子网端口。
port
服务端口号
基于现有集群的端口号的 BASE 来增长。
对应gp_segment_configuration系统表的
datadir
目录名称
datadir字段是数据库运行的系统表空间。
是系统中每个 Instance ID对应的是
整数不能与现有
gp_segment_configuration 系统表中的 dbid
dbid
Instance 有冲突
字段这个值是唯一的而且最好是连续且没有空
缺的。
是系统中每个 Instance content ID对应的
整数不能与现有
gp_segment_configuration 系统表中的
content
Instance 有冲突
content 字段配对的 Primary Mirror 具有
相同的值整个系统中必须是唯一且连续的。
Instance Primary 还是 Mirrorp 表示
preferred_role
p 或者 m
Primarym 表示 Mirror
GP6之前版本的扩容配置文件的格式是这样的
hostname:address:port:fselocation:dbid:content:preferred_role:replication_port
版权所有Esena(陈淼 ) 编写陈淼 - 357 -
Greenplum Database 管理员指南 V6.2.1
其中fselocation6版本中的datadir的含义相同都是数据库Instance
工作目录。replication_port6版本之前的概念指的是Instance与配对的
Primary或者Mirror进行同步的服务进程的端口如果要在6之前的版本自定义扩容
配置文件这个端口要格外小心因为很容易改出端口冲突的结果。
6版本中如果有除了缺省的表空间以外还有其他表空间还需要提供一个同
名且以(.ts)为后缀的表空间的配置文件其格式为
tableSpaceNameOrders=tablespace1_name[|tablespace2_name . . .]
tableSpaceOidOrders=tablespace1_oid[|tablespace2_oid . . .]
dbid|/path/for/tablespace1[:|/path/for/tablespace2 . . .]
dbid|/path/for/tablespace1[:|/path/for/tablespace2 . . .]
6之前的版本中如果除了缺省的文件空间以外还有其他文件空间还需要提
供一个同名且以(.fs)为后缀的文件空间的配置文件。其格式为
filespaceOrder=filespace1_name:filespace2_name: ...
dbid:/path/for/filespace1:/path/for/filespace2: ...
dbid:/path/for/filespace1:/path/for/filespace2: ...
注意在生成扩容配置文件之后如果要定制化Mirror策略请按照需要修改该文件
可以自由的将任意的Mirror放置到任意主机的任意目录下指定任意的端口不过
为了后期维护的方便还是建议按照某种规律来安排Mirror策略。
初始化新 Instance
在完成了扩容配置文件的准备工作之后就可以开始真正的扩容操作了这一步
才是真正的让 GP 数据库集群的 Instance 数量增加的操作之前一直都是在为这一步
做充足的准备工作因为一旦初始化新的 Instance 成功了是不可以回退的
要在这之前把性能测试做周密确保扩容后可以达到预期的效果。
这一步操作要么成功要么失败报错几乎没有什么步骤如果报错先进行扩
容回退然后根据报错的信息解决问题之后再重新尝试。
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 执行gpexpand命令通过-i参数指定扩容配置文件。例如
$ gpexpand -i input_file
版权所有Esena(陈淼 ) 编写陈淼 - 358 -
Greenplum Database 管理员指南 V6.2.1
如果是 6 之前的版本还需要配合-D 参数来指定一个用于存储扩容模式的数据库。
GP6 由于扩容过程中数据重分布的机制的变化不再需要特定的数据库来存储
这些信息而是内置使用 postgres 数据库来存储。
gpexpand 命令会检查是否已经有扩容模式存在如果有则不会继续执行
是报错退出所以如果之前已经扩容成功了要及时清理 gpexpand 模式通过执
gpexpand -c 来完成。如果在存储扩容模式的数据库中有用户定义的模式叫
gpexpand那么很不幸建议先修改这个名称待扩容完成之后再改回这个名称
编者想说的是在业务中使用这个模式名称一定是一位神人。
在完成了新 Instance 初始化并启动创建完成 gpexpand 模式生成重分布的
信息之后gpexpand 命令会输出成功的消息并退出。
在完成新 Instance 的初始化之后就可以在 postgres 数据库的 gpexpand
式中查看业务表的重分布的信息了。对于 6 之前的版本不是 postgres 数据库
而是-D 参数指定的那个数据库。
扩容失败回退
如果扩容失败了也就是 gpexpand -i 这一步操作出现了报错失败命令会
提示执行回退操作。如果此时数据库处于 Down 的状态需要先将 Master 启动
再执行回退命令启动 master only 模式使用 gpstart -m 来完成。
扩容失败的回退操作执行 gpexpand配合-r 参数或者--rollback 参数。例如
$ gpexpand -r
或者
$ gpexpand --rollback
注意如果扩容失败了回退之后首先要解决报错日志中提到的问题之后再重新尝
试扩容否则直接重新尝试可能会得到相同的失败结果。
数据表的重分布
完成了新Instance的初始化之后数据库加入了新的Instance也加入了新的
版权所有Esena(陈淼 ) 编写陈淼 - 359 -
Greenplum Database 管理员指南 V6.2.1
存储空间和计算资源但原有的数据仍然只存储在旧的Instance新的Instance
上还是空的。所以需要对数据表执行数据重分布的操作来重新平衡数据的分布。
在进行数据重分布时数据库是可以正常使用的实际上完成了扩容配置之后
新的Instance已经成功加入数据库集群之中从定性的角度来说扩容已经完成
便不进一步执行数据重分布操作数据库的规模也不能回退到扩容前的状态。
在完成了新Instance的初始化之后新创建的表数据是分布在包括新增
Instance在内的所有Instance上的此时的集群对于新创建的表来说和直接初
始化得到相同规模的集群效果是完全一样的。只是原有的那些表数据还是倾斜的
数据只分布在之前规模较小的集群这是通过gp_distribution_policy系统表的
numsegments字段来区分的。
调整表的重分布顺序
对于一个数据数据重分布耗时可能会很久的系统来说可以通过调整gpexpand
式下status_detail表的rank字段的值来调整数据表执行数据重分布的顺序让一
些更重要的表先执行数据重分布操作以尽早消除数据倾斜将数据倾斜的影响降到
最低。
要调整gpexpand.status_detail表的rank字段的值需要先连接到
postgres数据库(6之前的版本是gpexpand命令的-D参数指定的数据库)然后通过
UPDATE命令来修改rank字段的值。例如
=$ UPDATE gpexpand.status_detail SET rank=10;
=$ UPDATE gpexpand.status_detail SET rank=1 WHERE fq_name = 'public.lineitem';
=$ UPDATE gpexpand.status_detail SET rank=2 WHERE fq_name = 'public.orders';
这三条SQL命令首先是将所有表的优先级调整到10gpexpand生成的rank
缺省值是2。然后将public.lineitem这张表的优先级调整为1public.orders
这张表的优先级调整为2。当开始执行数据重分布操作时第一张被执行的表将是rank
值为1的表public.lineitem其次是rank值为2的表public.orders然后是
gpexpand.status_detail中记录的其他表。虽然可以将一些表的名称从
gpexpand.status_detail中删除这样gpexpand就不会对这些表进行数据重分布
的操作但是编者建议不要这么做因为这些表会一直以倾斜的状态遗留在系统中。
版权所有Esena(陈淼 ) 编写陈淼 - 360 -
Greenplum Database 管理员指南 V6.2.1
使用 gpexpand 重分布数据
一般来说执行数据重分布的操作都是通过继续执行gpexpand命令来完成
然这个命令还有很多不如意的地方比如gpexpand命令对每张表执行数据重分布
操作时都会显式的BEGIN事务和COMMIT事务Cache系统的类型这些动作
于一个规模很大的集群来说会额外消耗很多的时间。编者最近也为此花了不少心思
改写了gpexpand重分布逻辑UPDATE操作替换为INSERT在所有版本中都避免了
UPDATE的锁冲突同时重新写了一个脚本来解决数据重分布的显式事务开销问题
本来也想继续修改gpexpand但是发现动作太大还是重写一个脚本更实用。
使用gpexpand命令来完成数据重分布如同之前的两个阶段的操作一样就是执
gpexpand命令即可。
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 运行gpexpand命令。可以通过-d参数或者-e参数来指定数据重分布的时间。-d
参数确定的是运行多长时间-e参数确定的是结束的时间点。-d参数的格式是
hh:mm:ss-e参数的格式是YYYY-MM-DD hh:mm:ss。例如
$ gpexpand -d 60:00:00
命令会一直执行到所有的表都已经完成了重分布或者命令执行的时间长度达到
-d参数指定的长度或者-e参数指定的时间点。缺省的(产品自带版本)gpexpand
会在每完成一张表的数据重分布后修改gpexpand.status_detail表中的状态。
同时在开始和结束命令时gpexpand还会向gpexpand.status表中插入任务的开
始和结束的记录最后所有表都完成数据重分布时gpexpand.status表中会插入一
status值为'EXPANSION COMPLETE'状态的记录在此之后数据重分布全部结
再次执行gpexpand命令将会检测gpexpand.status表中是否有status值为
'EXPANSION COMPLETE'状态的记录如果有gpexpand命令将会直接退出。
监测数据重分布
在第二阶段初始化新的Instancegpexpand模式中会创建一个视图
名为gpexpand.expansion_progress在执行数据重分布期间可以查询该视图
来查看数据重分布的进展情况这个视图会展示整体的重分布情况包括未重分布的表
数量已经重分布的表的数量等信息如果在第二阶段指定了-S参数则会生成简单
信息的视图定义否则会生成信息更全的视图定义信息多自然需要收集的信息也
越多在生成表清单时在生成gpexpand.status_detail表的记录时需要
计算数据库集群中每张业务表的尺寸这是一个非常耗时的操作编者认为一般不需要
版权所有Esena(陈淼 ) 编写陈淼 - 361 -
Greenplum Database 管理员指南 V6.2.1
这些详细信息。
对于每张表的重分布情况可以查看gpexpand.status_detail表的记录
要是记录每张表的重分布信息是否还未开始何时开始正在重分布何时完成等。
假如在第二阶段未指定-S参数登录到postgres数据库(6之前版本是gpexpand
命令的-D参数指定的数据库)查询gpexpand.expansion_progress视图来查看数
据重分布的详细情况。例如
=# SELECT * FROM gpexpand.expansion_progress;
name
| value
------------------------------+-----------------------
Bytes Left
| 349539847977
Bytes Done
| 29872937423
Estimated Expansion Rate
| 891.2392397293 MB/s
Estimated Time to Completion
| 00:23:08.239082
Tables Expanded
| 32
Tables Left
| 293
(6 rows)
对于在第二阶段指定了-S 参数的情况来说该视图只会显示处于不同状态的表的
数量不会有尺寸的统计也不会有时间预估实际上时间的预估并不会很准确
为数据重分布的性能不完全与尺寸相关还与表的数量有很大关系尺寸为 0 的表
重分布的耗时并不是 0 因为事务的时间开销与数据量没有关系。
清除扩容用的模式
在完成所有的数据表的重分布操作之后需要清理gpexpand模式这样在以后
再进行扩容操作时才不至于因为gpexpand模式已经存在而导致操作报错。对于6
前的版本来说清理了gpexpand模式之后还有必要将专门用于扩容的数据库删除
切记在6之前的版本为扩容创建一个全新的空数据库扩容完成之后要清理并删除
该数据库。
1. 使用gpadmin用户登录到需要扩容的GP集群的Master主机。
2. 使用带-c参数运行gpexpand命令。例如
$ gpexpand -c
Do you want to dump the gpexpand.status_detail table to file? Yy|Nn
版权所有Esena(陈淼 ) 编写陈淼 - 362 -
Greenplum Database 管理员指南 V6.2.1
(default=Y):
> y
编者建议当询问是否将扩容的重分布信息备份为文件时建议选择备份以便
于以后还可以查看和再确认数据重分布的情况。
版权所有Esena(陈淼 ) 编写陈淼 - 363 -
Greenplum Database 管理员指南 V6.2.1
第十七章数据库的升级
目前能见得到的在用大版本基本上只有4.3版本5版本和6版本更早的版本
几乎已经见不到了所以这里也不做介绍了。目前已知的所有跨大版本的升级
是不能直接升级的比如4.3升级到5版本或者6版本5版本升级到6版本这些都
不能直接升级必须通过重建集群备份并恢复DDL迁移数据来间接的完成升级操
作。
小版本升级
小版本升级指的是Catalog版本号一致的版本之间的升级操作按照
Greenplum的版本规则4.3系列是一个大版本5系列是一个大版本6系列是一个
大版本在大版本内的升级全部属于小版本升级小版本升级主要是替换软件包
除此之外还可能会有一些函数或者功能的修补这些都会在官方的版本发布文档中有
详细说明。
升级条件
检查运行GP数据库的主机硬件环境以确保其符合GP数据库的运行要求。实际上
这个操作不仅仅是在升级之前要做在日常运行中也应该每个几个月做一次检查
根据每次的检查结果进行纵向对比以便于发现硬件性能的变化。
可以通过gpcheckperf命令来进行硬件的性能测试更多关于硬件性能测试的介
可以参考"系统性能检查"章节或者参考gpcheckperf命令的说明。
如果需要执行gpcheckcat命令应该在准备升级之前的几周之前确定一个维护
时间窗口因为执行gpcheckcat命令最好是在Restrict模式下进行如果发现了
Catalog问题需要在升级之前进行修复。
gpcheckcat命令位于$GPHOME/bin目录下在执行该命令时如果数据库不在
Restrict模式下可能会得到不准确的结果。
如果gpcheckcat命令检查出了Catalog的不一致可以尝试通过-g参数来生成
修复不一致的SQL脚本。不过并不是任何的Catalog不一致都可以自动生成修复脚本
版权所有Esena(陈淼 ) 编写陈淼 - 364 -
Greenplum Database 管理员指南 V6.2.1
的。在执行了修复的SQL脚本之后应该再次尝试执行gpcheckcat命令并生成SQL
以确保不再有Catalog不一致的情况。
注意只有一些简单的Catalog问题可以自动生成修复SQL如果gpcheckcat报错
且无法生成修复SQL可能需要专业技术支持来帮助解决这些Catalog问题。
如果在之前的版本配置了PXF需要在升级之前停止PXF的服务备份PXF
的配置文件以便于在升级之后恢复PXF的配置文件以及重新配置PXF服务。具体操
请参考PXF相关的文档说明编者不打算介绍任何PXF的内容。
如果在之前的版本配置了GPSS(Greenplum Streaming Server)同样需要
在升级之前停止GPSS的服务。在升级完GP数据库之后再根据GPSS的版本要求进行相
应的升级操作详情请参考GPSS相关的升级说明。
小版本升级步骤
1. 使用gpadmin用户登录到需要升级的GP集群的Master主机。例如
$ su - gpadmin
2. 确保数据库中没有事务在运行。例如
=# SELECT * FROM pg_stat_activity
WHERE state <> 'idle' AND pg_backend_pid() <> pid;
对于6之前的版本这个SQL是不同的。例如
=# SELECT * FROM pg_stat_activity
WHERE current_query <> '<IDLE>' AND pg_backend_pid() <> procpid;
3. 执行CHECKPOINT操作确保数据库的所有修改都能及时刷到磁盘。例如
$ psql -d postgres -c "CHECKPOINT"
4. 采用fast模式停止数据库使用-a参数不需要提示确认
$ gpstop -af
5. 上传新的GP软件安装包。
对于rpm安装包来说需要在所有主机上进行安装所以需要在每个主机上传安
版权所有Esena(陈淼 ) 编写陈淼 - 365 -
Greenplum Database 管理员指南 V6.2.1
装包比如上传到/tmp目录下。
对于6之前的版本来说如果使用的是bin安装包可以在Master上安装之后将
安装后的目录打包分发到所有其他主机进行解压。
6. 使用root用户登录安装GP数据库软件包。
例如对于RHEL/CentOS操作系统来说安装rpm安装包的方法
$ sudo yum install greenplum-db-<version>-<platform>.rpm
对于使用bin安装包的情况安装方法是使用bash命令。例如
$ sudo bash greenplum-db-<version>-<platform>.bin
根据交互式提示进行必要的输入以完成安装。
6版本已经支持Ubuntu操作系统Ubuntu操作系统安装rpm的方法
# apt install greenplum-db-<version>-<platform>.deb
7. 使用root用户修改安装目录的权限。例如
$ sudo chown -R gpadmin. /usr/local/greenplum*
8. 如果有必要修改MasterStandby主机上的greenplum_path.sh文件。例如
如果使用了LDAP认证需要修改greenplum_path.sh文件加入LDAP的信息
export LDAPCONF=/etc/openldap/ldap.conf
如果使用了PL/Java可能需要在greenplum_path.sh文件修改
JAVA_HOMELD_LIBRARY_PATH的设置。
最好将新版本的greenplum_path.sh文件与现有版本进行对比对于一些扩展
功能需要使用到的设置在新版本的greenplum_path.sh文件中进行同步的更
新。
9. 确保在gpadmin用户的.bashrc文件中已经正确的source了新版本的
greenplum_path.sh文件。例如
将如下的一行信息
source /usr/local/greenplum-db-<current_version>/greenplum_path.sh
版权所有Esena(陈淼 ) 编写陈淼 - 366 -
Greenplum Database 管理员指南 V6.2.1
修改为
source /usr/local/greenplum-db-<new_version>/greenplum_path.sh
如果使用的是软连接也可以修改软连接指向新的版本。例如
$ rm -f /usr/local/greenplum-db
$ ln -s /usr/local/greenplum-db-<new_version> /usr/local/greenplum-db
10. source新的.bahsrc文件或者使用gpadmin用户重新登录Master主机。例如
$ . ~/.bashrc
11. 使用gppkg命令来重新安装一个需要使用的GP扩展。例如pgcrypto, PL/R,
PL/Java或者PostGIS需要重新从Network官网下载对应新版本的安装包
并使用gppkg命令进行安装。
还有一些其他的需要更新的扩展文件比如JARso文件等一般来说对于小
版本升级这些文件是兼容的直接从现有版本的安装目录COPY到新版本的对应
目录即可。
12. 所有主机的安装目录都完成了更新升级之后就可以使用gpadmin用户来启动数
据库了。例如
# su - gpadmin
$ gpstart -a
13. 如果在之前的版本配置了PXF需要在升级之后重新初始化PXF服务。具体
操作请参考PXF相关的文档说明。
14. 如果在之前的版本配置了GPSS(Greenplum Streaming Server)在升级完
GP数据库之后需要根据GPSS的版本要求进行相应的升级操作详情请参考GPSS
相关的升级说明。
在完成升级之后应尽快确认所有功能都可以正常工作。
排查升级失败
如果升级失败请联系专业技术支持编者也没有这方面的经验总结故障总是有
各种各样的可能专业技术支持也是依靠报错日志的具体信息来判断问题并采取合
版权所有Esena(陈淼 ) 编写陈淼 - 367 -
Greenplum Database 管理员指南 V6.2.1
适的措施来解决故障。当然如果升级失败还可以考虑降回之前的版本。
大版本升级
要实施大版本升级将是一个复杂的工程编者建议如果有可能最好获得专业
技术支持的帮助。从4.3版本向5版本和6版本升级以及从5版本向6版本升级可以
使用标准的备份恢复命令来做也可以使用gpcopy来完成。编者提示备份恢复的方
式升级大版本有一定的限制。
注意GP开源版只有5版本之后才有5之前的版本都是商业版没有开源版。
注意目前不支持从4.3版本或者5版本直接升级到6版本也不支持从4.3版本直接升
级到5版本。所以这里介绍的大版本升级都是间接的升级方案。
本章节主要介绍大版本升级中可能遇到的一些问题尤其是从4.3版本做大版本升
级时会有比较多的语法等差异所以在从4.3版本做大版本升级时需要做一些必
要的修改以适应5版本或者6版本的特性。
准备一个新版本的 GP 集群
1. 使用新版本的GP软件部署一个新的GP集群。详情参见"安装部署与初始化"章节。
注意gprestore只支持将备份数据恢复到规模完全相同的集群而且
ContentID也必须保持一致。如果集群规模不同则无法使用gprestore恢复来
完成升级的目标。当然变通的方式也可以比如先建设一个相同规模的集群
完成了gprestore的恢复之后再对新版本的集群进行扩容。还可以使用gpcopy
等工具进行跨集群的数据迁移来完成不同规模集群的升级工作。
2. 安装部署gpbackupgprestore命令。商业用户可以从Network官网下载
商业版安装包或者开源用户可以从github下载源码进行编译安装。
3. 如果计划在现有集群的本地进行版本升级需要确保有足够的磁盘空间可以使用。
考虑到现有版本集群存储了PrimaryMirror占据了两份空间完整的数据库
备份需要占据一份空间新版本的PrimaryMirror也需要占据两份空间所以
整体上要占用5份空间那么现有版本集群的磁盘使用量需要低于40%。如果
可以采用离线备份将可以节省一些空间新版本集群采用只初始化Primary
方式也可以节省一些空间在完成升级之后再添加Mirror
版权所有Esena(陈淼 ) 编写陈淼 - 368 -
Greenplum Database 管理员指南 V6.2.1
注意不建议备份之后马上删除现有版本的集群万一通过备份来恢复集群的
操作出现异常将会导致灾难性后果。
如果集群的磁盘空间不足还想要在本地进行升级那么gpcopy命令提供的
--truncate-source-after参数是一种选择对于每一张表来说当数据成功
被同步到新集群后将现有版本的数据删除。这个方案并不是最佳的选择因为
一旦开始想要回退到之前的版本是非常困难的。
4. 在新版本的GP集群中安装现有版本中用到的扩展组件比如MADlibPostGIS
如果版本方面有不兼容的情况可能还需要针对涉及的表进行单独处理。
5. 如果在现有的版本中使用了Oracle的兼容函数包这个函数包在6版本中是不兼
容的6版本中使用数据库扩展组件的方式来支持Oracle兼容函数。例如
$ psql -d dbname 'CREATE EXTENSION orafce'
对于其他的扩展组件可以查看$GPHOME/share/postgresql/extension/
目录下的文件进行了解。目前6版本自带支持的扩展组件有
citext
hstore
dblink
orafce
diskquota
pageinspect
fuzzystrmatch
pgcrypto
gp_sparse_vector
sslinfo
6.
要恢复一些基于PL语言的自定义函数需要确保相关的LANGUAGE已经创建如果
涉及到自定义的so文件需要确保已经将特定的so文件已经按照新版本进行了编
译并放到了正确的路径。
7.
GP6中提供了更成熟和完善的资源管理方案资源组用于替换原有的资源队列
的方案。通过设置gp_resource_manager参数为queue或者group来选择使
用资源队列或者资源组。目前在6版本中这个参数的缺省值是queue但是从资
源组的发展来看未来应该会是逐渐取代资源队列成为缺省的资源管理方案。
如果是从4.3版本升级缺省不需要关注这个问题因为在4.3版本还没有资源组
的概念直接使用原有的资源队列即可完成升级过程。如果希望平滑的从资源队列
向资源组切换可以将资源组的内存管理模式保持与资源队列的行为一致可以通
过设置资源组的MEMORY_LIMIT属性和MEMORY_SPILL_RATIO属性为0来实现。
更多关于资源组的介绍可以参见"使用资源组"章节。
版权所有Esena(陈淼 ) 编写陈淼 - 369 -
Greenplum Database 管理员指南 V6.2.1
通过备份恢复的方式升级
如果要使用备份恢复的方式来升级GP数据库需要注意4版本中最低需要
4.3.22版本才能使用gpbackupgprestore命令5版本中最低需要5.5版本。
要在新版本恢复备份必须要先获得一个全量备份。
下面是一些通过备份恢复的方式从4.3或者5版本升级到6版本的一些已知的问题。
在进行升级时需要注意对现有版本进行相应的修改以使得相关的特性适配新的版本。
如果是从5版本升级到6版本且在5版本中配置了PXF则需要根据PXF的升级说
明来完成PXF的升级。
GP6不再支持gphdfs协议的外部表所以如果在之前的版本使用了gphdfs
协议的外部表那么在升级到6版本时需要删除这些外部表然后使用PXF
议来重新创建相应的外部表。
4.3版本、5版本、6版本之间系统表以及系统表的字段有了很多变化。所以
进行大版本迁移时需要注意这些差异。
6版本中pg_class系统表的reltoastidxid字段被删除。
6版本中pg_stat_replication系统视图的procpid改为了pid
6版本中pg_stat_activity系统视图的procpid改为了pid
6版本中gp_distribution_policy系统表的attrnums字段改为了
distkey增加了numsegments字段用于标识数据表的数据分布在多少个
Instance上。
6版本中删除了Filespace的概念所以也删除了pg_filespace
pg_filespace_entry两张系统表。
对于DDL备份来说如果UDF引用了的自定义类型或者其UDF而该自定义类
型或者UDF的定义在DDL备份文件的后面部分UDF的恢复会失败不过可
以尝试多执行几次DDL恢复来解决这类依赖问题。
4.3版本可读外部表支持INTO error_table而该特性从5版本开始已经被
废止虽然目前可以通过设置gp_ignore_error_table参数为ON来避免INTO
error_table语法报错但是已经没有error_table所以外部表的定
义需要修改。
6版本中不再提供只有一个参数的string_agg函数在以前的版本中提供了只
版权所有Esena(陈淼 ) 编写陈淼 - 370 -
Greenplum Database 管理员指南 V6.2.1
有一个参数的string_agg函数其效果与第二个参数为空字符是相同的。
6版本中leadlag函数的第二个参数offset的参数类型从bigint改为了
integer4.35版本中该参数的类型是bigint
通过备份恢复的方式来升级GP版本会面临一个问题那就是分布键字段在大版本
之间有些字段的类型其底层的二进制实现发生了改变。这种情况将会导致
gprestore不能正确的进行数据分布。这种情况在目前的4.3版本、5版本和6
本之间都有存在。所以如果可以使用跨集群传输数据的方式来完成大版本升级
将不会发生这种情况因为gprestoreInstance本地的COPY恢复时不会
有数据重分布的动作然而跨集群传输数据一般采用外部表的方式会自动进
行数据重分布。
6版本中abstimereltimetintervalmoneyanyarray这些类型
不能用于分布键。
6版本中YYYYMMDDHH24MISS这种日期格式不支持直接转换为timestamp
类型。在4.3版本和5版本这种日期格式是可以直接转换为timestamp类型的
所以这可能会是一个很麻烦的问题比如外部表加载的数据中有这种格式的时
间字段那就很痛苦了。从用户的易用性角度来说编者希望能重新支持这种格式。
在有些版本中CREATE TABLEDISTRIBUTED BY子句允许指定重复的字段作
为分布键而后来这个问题被修复了不再允许这种错误的行为但是gpbackup
备份出来的DDL信息中分布键字段会包含这种重复字段。所以选择一个更好的
DDL备份恢复工具对大版本升级也很重要。
4.3版本和5版本中allow_system_table_mods隐藏参数的可选值有none
ddldmlall(all不能在Session中设置)6版本这个参数变成了布尔
只能是ONOFFTRUEFALSE
5版本开始TEXT类型的隐式类型转换功能不再支持。
5版本开始MoneyNumeric等类型的底层实现发生了变化使用这些类型的
字段作为分布键的表数据分布规律将发生改变。
5版本开始反斜线(\)缺省不再表现为转义符。而是需要使用(E'. . .')
方式来显式的表明字符串中的反斜线是转义符。
在进行大版本升级之前做充分的测试是非常重要的。而且备份恢复的方案未必
能够顺利的完成大版本的升级编者建议应该优先考虑数据同步的方案。大版本升级
不仅涉及数据的搬迁还涉及DDL的备份和修改适配业务SQL的修改适配各种管理
工具和客户端的适配。比如4.3版本和5版本6版本的系统表差异较多一些客户端
工具会有各种各样的因系统表的不适配而导致语法报错。
版权所有Esena(陈淼 ) 编写陈淼 - 371 -
Greenplum Database 管理员指南 V6.2.1
通过数据同步的方式升级
1. 初始化新版本的集群如果要进行本地升级需要注意Instance的工作目录和端
口的配置不能与现有集群有冲突。
2. 现有集群DDL备份。可以使用pg_dumppg_dumpall等命令编者也编写了一套
DDL的备份与恢复命令可以根据即将用于恢复的版本确定备份的DDL的输出格式
基本上不需要进行修改即可在新版本集群进行DDL的并行恢复。例如
$ gpddlbackup --database gpmagic -f gpmagic.ddl --target-version 6
3. 在新版本集群恢复DDL。例如
$ gpddlrestore --database gpmagic -f gpmagic.ddl --object-bit 03FD
在目标数据库上恢复DDL可以指定恢复的DDL的类型比如此例中暂时不恢复
索引信息等数据完成同步之后再恢复索引信息以确保数据同步的性能。
在恢复DDL仍可能会有个别的错误信息比如FILESPACE信息不会备份
对于6之前的版本可能需要修改TABLESPACE定义的FILESPACE属性为已存在的
文件空间名称。
4. 执行跨集群的数据同步命令。例如
$ gpdbtransfer --parameter-file parameter_file
其中parameter_file是一个参数文件这样便于进行参数的维护便于多次执
行命令。
5. 交换现有集群和新版本集群的端口。
注意无论哪种大版本升级方案都务必做好测试工作确保所有业务和功能在新版本
上可以良好运行。在升级过程中再去临时解决突发问题将会导致难以控制的时间成本。
注意这里示例的命令是编者自己编写的命令仅对编者服务的用户提供。类似的
以通过数据库自带的备份恢复命令完成DDL信息的备份和恢复使用gpcopy命令实现
跨集群的数据同步。
版权所有Esena(陈淼 ) 编写陈淼 - 372 -
Greenplum Database 管理员指南 V6.2.1
第十八章最佳实践
最佳实践不是从源码得到的结论而是众多实施经验的总结是通过长时间的积
经过多次的验证最终得出的经验性结论。最佳实践更符合科学的方法论是对实
践经验的总结和归纳可以更好的预期不同执行方法的结果。同时最佳实践不仅仅
是对过去的现象和经验的总结归纳而是经过无数次的检验和再总结的结论综合多方
面的技术和知识得到的系统性结论。
这部分内容编者还是第一次开始编写所以主体框架会以官方文档为基础
可以预见到的是这个章节将是编者的见解与官方文档差异较多的章节。
本章节不会像其他章节那样介绍GP数据库的功能细节和如何操作而是重点
在讲述如何做才是最好的选择也就是所谓的最佳实践。
掌握了更多的最佳实践的知识对于GP数据库的运维管理、性能优化等工作
可以起到很好的指导作用也可以帮助很多初学者解决一些概念上的困惑。
最佳实践概述
本节将大概介绍一下最佳实践的多个方面的内容。
数据模型
GPMPP数据库主要专注在分析型场景所以与传统的单机交易型数据库在模
型设计上会有所不同。因此GP更推荐如下的模型设计
对于非范式模型GP数据库将会表现出更好的性能。比如星型模型和雪花模型
数据库中的数据将以大数据量的事实表和小数据量的维表来进行存储。
不同的表之间有关联关系的字段采用相同的字段类型。
版权所有Esena(陈淼 ) 编写陈淼 - 373 -
Greenplum Database 管理员指南 V6.2.1
Heap 表与 AO
对于有高频度单条INSERTDELETEUPDATE操作的表和分区来说采用Heap
表会更适合这与Heap表和AO表的底层存储结构有关。
对于有高并发单条INSERTDELETEUPDATE操作的表和分区来说采用Heap
表会更适合。这是对于6版本来说的需要配合GDD(全局死锁检测)的功能来支持
6之前的版本所有表的UPDATEDELETE操作都需要EXCLUSIVEHeap
也是一样所以6之前的版本并发的单条UPDATEDELETE操作是排队的。
对于只会进行大数据量的批量操作的表来说采用AO表更适合。对于AO不适
合高频度的单条INSERTDELETEUPDATE操作也不适合高并发的单条INSERT
DELETEUPDATE操作。AO在设计上允许最多128个并发INSERTDELETE
UPDATE操作不能真正的并发执行需要获取EXCLUSIVE进行排队执行。
要避免在AO表上执行单条INSERTDELETEUPDATE操作。
要避免在AO表上执行并发DELETEUPDATE操作。虽然支持并发INSERT操作
并发INSERT会导致AO表的数据文件分裂从而导致文件数的膨胀最多会膨
胀到128一旦出现大规模的AO表文件数膨胀会对IO性能造成极其严重的影
大量的AO表文件数膨胀还会影响文件系统的性能。
行存与列存
对于有高频度单条INSERTDELETEUPDATE操作的表和分区来说采用行存表
会更适合可以表现出更好的性能。
对于需要查询很多字段的表来说采用行存表会更适合。
对于用途较广或者有混合负载的表来说采用行存表会更合适。
对于表中字段较多而只对少数字段进行查询和聚合的场景采用列存表会更有优
势。需要注意的是编者建议如果使用行存表能够满足需求优先采用行存表。
对于只会定期修改个别字段的表来说采用列存表会更有优势。需要注意的是
者建议如果使用行存表能够满足需求优先采用行存表。
注意虽然在有些情况下列存表会更有优势但是不等于说只要符合这样的条件就要
用列存。至少目前的AO表技术为了支持并发INSERT底层的数据文件是会分裂的
版权所有Esena(陈淼 ) 编写陈淼 - 374 -
Greenplum Database 管理员指南 V6.2.1
最多会分裂为128倍的文件个数所以如果再加上列存的因素列存表每个字段单
独存储一个数据文件列存表的并发INSERT会导致数据文件的个数严重失控会带来
近乎灾难性的后果。更多介绍参见"选择行存或列存"章节的介绍。
压缩
对于不适合使用Heap表的大型事实表或者分区表应该采用压缩表(压缩表必须是
AO)。压缩表可以降低IO的压力节省磁盘空间。
编者建议不要试图为列存表的不同字段设置不同的压缩属性因为毫无意义。
在压缩级别和性能之间需要寻找一个平衡越高的压缩级别一般来说意味着更
好的压缩效果同时会消耗更多的CPU资源来完成压缩和解压计算。编者认为
6版本开始16级的ZSTD压缩是最理想的可选范围如果对于压缩效果不是
特别敏感也许1ZSTD压缩是最好的选择6之前的版本选择36级的ZLIB
压缩是最好的选择。
分布键
对任何表明确指定分布键或者使用随机分布而不是依赖缺省的行为。
只要有可能应该只使用一个字段作为分布键而不是使用组合字段作为分布键。
如果不是为了特定的目的设计不要为分析型用途的表选择WHERE条件包含的字
段作为分布键。比如查询是主键查询使用主键作为分布键并不会有任何不妥
反而是最合适的设计这一条的主要表达的意思是不要让个别实例来承担一个大
的查询任务。
应该尽可能的避免使用日期或者时间字段来作为分布键。因为一般不会使用这种
字段来与其他的表进行关联查询。
不要用分区字段作为分布键。因为一般不会使用这种字段来与其他的表进行关联
查询。
为了改善大表之间的关联性能应该考虑将大表之间关联的字段作为分布键。注意
这里说的是大表之间的关联但凡涉及与小表关联的场景完全不应该作为选择分
布键的考虑因素。
版权所有Esena(陈淼 ) 编写陈淼 - 375 -
Greenplum Database 管理员指南 V6.2.1
要定期或者不定期的检查数据分布的倾斜情况。可以参考"数据的分布与倾斜"
节获得更多关于检查数据倾斜的信息。
注意如何界定分布键的选择是否合理以大型任务计算不倾斜为最高目标。
内存管理
GP数据库要求设置vm.overcommit_memory2。对于overcommit的三种选择
012对应了不同的行为0允许适度的超限申请内存1允许无节制的超限
申请内存2禁止超限申请内存。为什么GP要求配置为2因为对于01
种情况都有可能会触发oom-killer一旦触发该行为将无法确保数据库主服
务进程一定不会被选中成为被kill的进程那将是十分危险的。
要禁用hugepage特性。主机的内存分配的控制应该由GP数据库来统一管理。
设置好GUC参数gp_vmem_protect_limit以控制在启用资源队列的情况下
每个Instance所能使用的内存的上限。这个GUC参数的设置一定要遵循GP的要
不能想当然乱改。
gp_vmem_protect_limit的值可以这样来计算
编者并不清楚官方文档中的公式是如何得来的难以理解所以编者不会介绍搞
不清楚的公式编者按照自己的理解和实践经验来介绍。
首先将主机物理内存的90%作为GP的可用内存。
GP可用内存 = 物理内存 × 90%
这里不考虑SWAP的尺寸原则上SWAP尺寸与Mirror策略有关通用的方案是
SWAP尺寸与RAM尺寸相同但是SWAP只是为了保障可能发生Mirror切换时内存
不足的情况在集群健康的情况下应该永远都不要用到SWAP
对于每个Primary来说可用内存的量与主机上Primary的数量成反比。
gp_vmem_protect_limit = 物理内存 × 90% ÷ 主机上Primary数量
得到的结果换算为MB为单位的数字就是gp_vmem_protect_limit参数的值。
至于为workfile预留的内存尺寸编者认为可以选择忽略。
版权所有Esena(陈淼 ) 编写陈淼 - 376 -
Greenplum Database 管理员指南 V6.2.1
绝对不要将GUC参数gp_vmem_protect_limit的值设置过高甚至主机上所有
Primarygp_vmem_protect_limit的值的和超过物理内存。
编者建议vm.overcommit_ratio的值设置为95对于SWAP只是一个保障
前面在计算gp_vmem_protect_limit的时候编者并未引入
vm.overcommit_ratio这个参数目标很明确在健康的情况下确保GP绝对
不会用到SWAP在异常情况下算上SWAP的尺寸确保绝对不会超出最大可用内
存尺寸。
对于内存分配尺寸受statement_mem控制的场景可以使用statement_mem
数来控制每个Instance的内存使用上限。
结合资源队列的活动语句数限制(ACTIVE_STATEMENTS)和内存限制
(MEMORY_LIMIT)来控制资源队列中语句的内存使用量。
将所有用户都配置合适的资源队列或者资源组而不是使用缺省的配置这样有利
于按照预期去控制每个用户的资源使用情况。
注意编者认为对于资源队列的内存限制也许没有很大的必要通过设置资源队列
的内存限制来控制查询的内存开销可能意义更是不大因为这些内存并不是总有语句在
使用合理的超限配置与任务的交叉可能会更有利于内存的充分利用。
分区
只对特别大的表进行分区--这是所有条件中必须满足的条件不满足该条件的任
何表都不应该进行分区。永远不要对小表进行分区哪怕它的表结构和应用场景
非常的具有周期性和规律性。
选择分区字段时要确保该字段可以用于查询条件从而可以进行分区消除以降
低查询扫描的数据量。
如果可以选择范围(range)分区最好不要选择列表(list)分区。列表分区
个分区对应的都是孤立的值对于只有有限个DISTINCT值的字段进行分区
往没有必要因为不会带来显著的性能提升。
要选择常常会用于过滤条件的字段作为分区字段。
不要用分布键作为分区字段。
不要使用缺省分区。PostgreSQL优化器一定会扫描缺省分区而且有缺省分区
的情况下添加分区必须通过split缺省分区来完成。
版权所有Esena(陈淼 ) 编写陈淼 - 377 -
Greenplum Database 管理员指南 V6.2.1
杜绝使用多级分区多级分区很容易使得表的数量失控从而导致文件数失控。
需要合理控制分区粒度不要过度零碎的进行分区。每个叶子分区在每个
Primary上的数据量应该控制在100MB以上或者记录数在100万条以上。比如集
群有100Primary那么可以使用一个通用的简化标准每个叶子分区的数据量
1亿条以上。同时单表在单个Primary上的记录数低于500万条时建议不
做分区比如集群有100Primary单表记录数在5亿以下时可以不分区。
应该检查执行计划是否有分区裁剪以确定分区是否对查询有帮助。
当需要对列存表进行分区时每个分区的记录数应该更大因为列存表是按照每个
字段作为一个单独的数据文件来存储的。整个分区表的数据文件数量为
文件数量 = Primary数量 × 分区数量 × 字段数量
比如100Primary的集群一张表有100个分区100个字段那么数据文
件的数量就会达到100万个如果再有多并发INSERT导致AO表文件分裂最坏的
情况下文件数将达到1.28亿个每个Primary上的文件数最坏的情况下
以达到128万个这些数字都是极其糟糕的。
在对列存表进行分区时应该控制每个叶子分区在每个Primary的记录数在
1000万以上。
注意编者认为合理的分区对于大表的查询性能提升和数据周期管理都有很大帮助
所以应该合理的使用分区表但是绝对不要过度分区也不要完全不用分区。
索引
通常来说GP数据库不依赖索引。也就是说索引通常不是一种优化手段
些类似交易型场景索引的确会有帮助而分析型场景索引不会带来任何好处。
对于高选择性的查询可以在相关的字段上创建索引以提升查询的性能。如果这
种查询很少发生则创建索引的代价可能会远远超过带来的收益所以应该只为
高选择性且会多次使用的查询场景考虑使用索引来提升高性能。
避免为高频更新的字段创建索引。索引字段的更新一定会导致索引的更新从而导
致索引的膨胀严重的甚至导致索引失效。
对于加载数据量较大的场景应该考虑删除索引后再加载数据在完成数据加载后
重建索引。这个比较难找到一个确切的界限当需要加载的数据量不是很大也不
版权所有Esena(陈淼 ) 编写陈淼 - 378 -
Greenplum Database 管理员指南 V6.2.1
是很小时重建索引未必会比直接带索引加载更快所以这需要根据经验来衡量。
应该为高选择性字段创建B-tree索引而不是Bitmap索引。
对于需要被更新的字段不应该使用Bitmap索引。编者认为实际上Bitmap
GP数据库中几乎没有存在的价值因为GP数据库中数据是分散的
看一个Primary上的数据选择性会比从整个集群角度看到的选择性高很多。
对于分区表尽量不使用索引如果必须使用索引一定要与分区字段不同。
更多关于使用索引的说明可以参见"GP中使用索引"章节。
资源队列
资源队列的最大作用是控制活跃语句数量从而控制资源的争抢程度。编者想要解
释一下为什么要控制活跃语句数量这与资源有关一定的硬件环境计算能力
是有限的太多的任务同时在执行会使得系统资源出现严重的争抢从而导致计
算效率严重下降。无论什么批处理系统追求的最高目标永远是任务量一定的情
况下用最短的时间执行完所有的任务而不是同时有更多个任务在执行。
所有的角色都应该设置合适的资源队列。
通过资源队列的ACTIVE_STATEMENTS属性来限制活跃语句的数量。
还可以通过资源队列的MEMORY_LIMIT属性来限制内存的使用量。不过编者建议
一般不太需要这样做除非内存资源过于紧张经常出现内存不足的报错。
根据批处理的情况适当的对资源队列的属性做出调整。
注意应该考虑逐步使用资源组来代替资源队列资源组对资源的控制粒度更细致。
监控与维护
要对系统表和数据库日志有日常的监控和维护。比如系统表的定期VACUUM
VACUUM FULL系统表索引的定期REINDEX(6之前的版本pg_class
REINDEX操作会导致pg_class表本身的索引的位置被更新到表的最后的page
这是需要注意的问题所以一般来说6之前的版本不对pg_class进行
版权所有Esena(陈淼 ) 编写陈淼 - 379 -
Greenplum Database 管理员指南 V6.2.1
REINDEX操作万一做了并导致了性能问题请联系专业技术支持)
定期使用gpcheckperf命令对集群进行性能检查并记录结果以便于进行纵向
对比提前发现严重的性能下降趋势和可能存在的性能故障。
运用各种监控工具来记录系统的负载情况包括且不限于CPU资源、内存资源、IO
资源和网络资源的使用情况。
对任何异常和故障进行根本原因分析。这将有助于找到问题的根本原因提前发
现可能出现的问题和风险避免一些可能有问题的相关操作。
对系统中运行性能较差或者耗时超过预期的查询检查其执行计划寻找可能的优
化方法提升系统的运行效率降低系统运行压力。很多系统一直在可接受程度的
边缘苦苦支撑不求深度优化这是错误的系统的高压运行不仅仅是影响应用
的效率还会为硬件增加严重的压力降低整个系统的稳定性。
检查执行计划确保是否正确的进行了分区裁剪或者索引扫描。这不是说建议使用
分区和索引而是要确保已经进行了分区的表已经建立了索引的表这些措施
和代价是否真正带来了性能的提升否则分区和索引的代价就是徒劳的。
弄清楚各种日志的位置和内容并进行必要的监控。比如pg_log日志中及时发
PANIC报错信息及时的排查原因。
注意并不是每个早期用户都善于进行监控与维护工作对于商业用户来说专业技术
支持的定期巡检工作中会对GP集群进行必要的检查和维护并会根据巡检的结果
给出专业的监控与维护的建议甚至会提供专业的命令和脚本用于日常的监控与维护工
作。不断的改进监控与维护措施可以保障GP数据库长期高效而稳定的运行。
收集统计信息
GUC参数gp_autostats_mode设置为on_no_stats(这也是缺省设置)并不
能避免需要ANALYZE。如果将GUC参数gp_autostats_mode设置为on_change
并且GUC参数gp_autostats_on_change_threshold设置为一个较小的值
(比如几百万)可以减少手动ANALYZE但是这样做会带来很大的资源开销
同时没有一个合适的阈值(不存在最佳设置)可以永远避免手动ANALYZE
在有些时候可以考虑使用analyzedb命令来收集数据库的统计信息。这个命令
的优势是可以进行一定的增量识别距离上次analyze之后没有发生过变化
的表不会再次被analyze。不过analyzedb和其他的很多数据库命令一样
法识别Heap是否发生了变化只能识别AO表是否发生了变化。
版权所有Esena(陈淼 ) 编写陈淼 - 380 -
Greenplum Database 管理员指南 V6.2.1
在需要的时候针对特定的表执行ANALYZE操作。
在大规模数据量发生变化的INSERTDELETEUPDATE操作之后有必要执行
ANALYZE操作。
有必要在CREATE INDEX之后针对索引字段进行ANALYZE以收集统计信息。
如果全字段执行ANALYZE收集统计信息的性能较差可以只针对JOIN条件字段、
WHERE条件字段、排序字段、GROUP BY字段和HAVING字段进行统计信息的收集
对于只在结果中出现的字段永远没有收集统计信息的必要。
在对大量的表进行数据修改后可以执行analyzedb命令来更新统计信息比如
扩容升级等操作之后通过analyzedb命令可以并行快速的收集统计信息。
回收空间
在进行大量数据DELETEUPDATE操作之后应该对表进行VACUUM操作。不过
编者建议有时候REORGANIZE也许会是更好的选择尤其是Heap因为Heap
VACUUM并不会真正的将空间返给操作系统只是把垃圾空间记录下来以便重
新利用。而对于AOVACUUMVACUUM FULL无法降低因为并发INSERT导致的
文件数膨胀问题只有REORGANIZE可以解决该问题(编者实测所有版本如此)
对于业务中使用的Heap不要进行VACUUM FULL操作性能不好应该使用
REORGANIZE来完成空间的彻底回收。而对于AO如果不需要解决并发INSERT
导致的文件数膨胀问题则直接执行VACUUM即可AO表的VACUUMHeap表不同
AO表的VACUUM会将空间返回给操作系统。
对于系统表需要定期进行VACUUM操作如果长时间没有进行VACUUM操作
可能会需要执行VACUUM FULL来回收空间这与业务Heap表不同系统表不能进
REORGANIZE操作所以在必要的时候必须进行VACUUM FULL
对于系统表的VACUUM官方文档建议不要kill是的任何数据库进程都不要
kill但是可以cancel--至少在必要的时候可以这样做编者建议也应该尽
量避免cancel最好在一个空闲时间来做系统表的VACUUM
数据加载
版权所有Esena(陈淼 ) 编写陈淼 - 381 -
Greenplum Database 管理员指南 V6.2.1
Primary的数量越多并行数据加载的能力就越强这一点毋庸置疑不过
际的性能还与其他因素有关比如文件服务器的CPU性能磁盘性能和网络带宽等。
如果集群规模特别大需要加载的数据量特别大单个文件服务器的性能无法满足
数据加载的要求可以配置多个文件服务器使得数据文件尽量均衡的分布在多个
文件服务器上。
将数据量特别大的文件均分到多个文件服务器上可以充分利用多个文件系
统的性能。这是因为单个文件系统的性能是有限的。
在一个文件系统上运行多个gpfdist服务。这是因为单个gpfdist服务的
性能是有限的实际上gpfdist缺省按照32KB一个block来切分文件
能表现并不好如果采用128KB512KBblock来切分文件会有极大的
性能提升而且gpfdist是单进程服务一边切分数据文件一边给request
发送数据如果把数据发送改成异步单个切分文件的进程性能完全可以
达到3GB/S甚至4GB/S而一边切分数据文件一边发送数据的方式最高
可以达到大约1.5GB/S的性能。
官方文档说尽可能在多个网络端口上运行gpfdist编者想说gpfdist
一般都是直接监听IPV40.0.0.0地址和IPV6::地址gpfdist服务本
身并不区分网络端口真正利用多个网络端口的方法是在外部表中使用不
同的子网端口来访问gpfdist服务。还有就是gpfdist和外部表之间没有
使用压缩传输如果使用压缩传输可能就不会有网络问题了。
通过GUC参数gp_external_max_segs来控制通过gpfdist外部表访问
gpfdist服务的Primary数量。尤其是网络环境比较差的时候可能需要降
低该参数的值以缓解网络压力过大导致的异常。
官方文件建议保持gp_external_max_segs数量是外部表中location
数量的倍数。这可能是出于压力均衡的考虑这个需要基于一个前提假设
那就是每个location指向的资源是均衡的这个前提假设在生产中其实
很难保证。
编者认为如果能把gpfdist协议做到并发压缩传输这些问题都将不是问
一个gpfdist利用多个CPU线程的资源就可以使得切分发送文件的性
能达到3GB/S甚至4GB/S市面上的主流服务器的IO性能也不过如此。
在装载较大尺寸的数据之前应该考虑先删除索引等数据装载完成之后再重新
创建索引。需要提醒的是这句话说起来很轻松但实际操作却困难重重比如一
个几十亿条记录的表重建索引的代价也很大重建索引期间将没有索引可用。
因此在条件允许的情况下通过表交换的方式可以大幅减轻对现有业务的影响
比如有规律的分区表通过交换分区的模式来新增数据非分区表通过交换表名
的方式来新增数据不过这种操作一般只适合批处理操作对于持续的交易型操
没有特别好的办法。
版权所有Esena(陈淼 ) 编写陈淼 - 382 -
Greenplum Database 管理员指南 V6.2.1
账户安全
保护gpadmin账户不允许普通用户使用该账户只有核心管理人员可以使用。
只在特殊情况下使用gpadmin账户比如系统维护、升级、扩容、故障处理等。
必须严格控制SUPERUSER权限的分配因为SUPERUSER可以跳过所有的权限限
制和资源队列的限制甚至不应该将任何普通角色加入具有SUPERUSER权限的
用户组--这样做也是有很大风险的因为SET ROLE命令可以获得GROUP的权限。
批处理应用业务应用ETL应用都不应该使用gpadmin用户。要把SUPERUSER
权限关在笼子里否则会有很多麻烦。
为不同的用户分配不同的数据库角色。
使用用户组来来管理对象的访问权限尽量不直接对可登录的数据库账户赋权
样便于数据库账户的维护和权限管控。
保护好GP数据库集群中操作系统的root用户和gpadmin用户密码并设置复杂且
不容易被猜测的密码。
保护好操作系统的重要文件的访问权限不能被普通用户随意修改。
高可用
机械磁盘要做Raid单个Raid 5的磁盘数量不宜过多目前主流的2GB Cache
的双通道Avago(以前叫LSI后来被Avago收购了)Raid采用Raid 5
Raid组的磁盘数不宜过多一般建议最多12块为佳2UX86主机24SAS
机械盘满配时建议划分为2Raid连续读写性能可以达到2.5GB/S4GB/S
的范围。
如果有条件建议采用Raid 1Raid 5或者Raid 6Raid策略以满足磁盘
故障时可以继续提供服务的目标。不过Raid 1要损失50%的磁盘容量Raid
6会大幅增加Raid卡的压力所以一般还是建议采用Raid 5的方案。
对于更换磁盘比较复杂的环境建议设置HotSpare热备盘这样可以避免单盘
版权所有Esena(陈淼 ) 编写陈淼 - 383 -
Greenplum Database 管理员指南 V6.2.1
故障后长时间不进行更换导致的灾难性后果。编者建议对于可以随时更换故障磁
盘的环境热备盘未必是一个更好的选择热备盘的Rebuild动作是自动的
不会因为任务多压力大而暂停所以Rebuild期间Raid的性能比坏一块盘
的情况还要糟糕如果更换磁盘的周期很短建议不配置Hotspare而是在发生
单盘故障之后选择一个任务空闲时段更换磁盘并进行Rebuild操作。
定期监控Raid的状态和磁盘的健康状况及时发现Raid和磁盘的异常状态并能
够及时采取措施进行修复。
定期监控磁盘使用率在必要时提前规划扩容。GP数据库要求磁盘使用率不
能超过70%这是一条永远都不应该触碰的红线GP数据库长期运行在磁盘利用率
高于70%的状态可能会导致多种难以控制的问题比如磁盘碎片率突增磁盘
性能陡降最终体现在数据库上的是性能下降严重数据库效率低下。
定期检查主机之间的磁盘容量是否发生倾斜。
Master配置Standby。如果没有StandbyMaster出现灾难性故障会导
致集群不可用更严重的可能会导致数据难以恢复的灾难性后果。在配置了
Standby的情况下应该密集的监控MasterStandby的同步状况并及时处理
同步丢失的问题确保Standby总是与Master保持同步状态。
设计好Master切换到Standby的后续工作确保客户端的访问可以顺利过渡
MasterStandby设置共用的虚拟IP地址在激活Standby之后将虚
IP漂移到Standby所在主机。当然采用动态DNS也是一种选择只是编者觉
这可能比采用虚拟IP要复杂的多。
为系统配置消息通知在发生Instance故障时及时通知运维和管理人员。
Primary配置Mirror。这很重要如果没有Mirror任何一个Primary发生
故障整个GP数据库集群就会进入不可用状态。
Mirror总是位于与Primary不同的主机上。关于Mirror策略有多种模式
处不再展开说详情可以参见"Instance镜像"章节。
当出现了Instance故障应该尽快恢复集群的高可用状态在执行
gprecoverseg命令之前最好找到Instance故障的原因并解决否则集群恢
复之后未解决的故障仍可能成为潜在的风险或者影响集群的运行性能。
可以通过部署冗余集群的方式实现灾备同时可以获取更高的查询能力。截止目
前的6版本GP还没有实现原生的容灾功能或者双活集群所以目前还是通过变
通的方案来实现灾备目前编者的增量异地同步方案是已知最先进的方案。
如果GP集群部署了备份方案绝对不应该在计算主机的本地磁盘上保存备份数
据文件应该采取离线存储的方式否则一旦计算主机出现灾难性故障备份数
版权所有Esena(陈淼 ) 编写陈淼 - 384 -
Greenplum Database 管理员指南 V6.2.1
据文件也会随之丢失就失去了备份的意义。
建议将数据保存到NFS目录从而实现备份文件的离线保存NFS文件服务器的性
能要有保障避免因IO瓶颈影响备份的性能每个计算主机生成备份压缩文件
的速度可以按照250GB/小时到500GB/小时进行评估。
系统配置
对于安装配置GP数据库主机初始化GP数据库集群的管理员来说应该按照最佳
实践的要求来修改和配置操作系统参数和GP数据库参数。
本节介绍的最佳实践的配置如果使用编者的自动化安装部署初始化命令来进行一
键式GP数据库集群的安装部署会自动完成这些最佳实践的配置并不需要关心每一
项的细节目前已经做到执行一条命令自动完成全部最优化设置的目标编者自称
其为最先进的GP数据库自动化安装部署命令不过目前只服务商业付费用户。
文件系统
GP数据库要求工作目录必须运行在XFS文件系统上因为XFS文件系统在处理大尺
寸文件时的性能更具优势RHELCentOS系统使用如下的XFS挂载参数
rw,nodev,noatime,nobarrier,inode64
由于Ubuntu操作系统不支持nobarrier挂载参数所以使用如下的XFS挂载参数
rw,nodev,noatime,inode64
早些年的版本中会提到一个挂载参数
allocsize=16M
注意这个挂载参数已经被证明是一个不应该使用的挂载参数这个参数除了会带来
麻烦并不会带来任何的好处因为针对所有的空间请求XFS第一次都分配16MB
极其浪费的在一些极端场景甚至会导致磁盘空间突增直至空间不足。
版权所有Esena(陈淼 ) 编写陈淼 - 385 -
Greenplum Database 管理员指南 V6.2.1
端口范围配置
6版本的安装文档中已经使用了新的端口范围配置规范新的规范是直接将
GP的服务端口范围从ip_local_port_range中扣除。官方文档的建议配置为
/etc/sysctl.conf文件中设置
net.ipv4.ip_local_port_range = 10000 65535
基于上述配置GPInstance的服务端口选择小于10000的端口。例如
PORT_BASE = 6000
MIRROR_PORT_BASE = 7000
编者不喜欢这种过于粗陋的方式还是更喜欢如下的配置方式
/etc/sysctl.conf 文件中设置
net.ipv4.ip_local_port_range = 1025 65535
net.ipv4.ip_local_reserved_ports = 5432,40000-40005,50000-50005
GPInstance的服务端口进行保留而不是扣除更多无关的端口。
IO 参数配置
设置GP数据库运行目录所在的磁盘设备的blockdevread-ahead尺寸为
16384这个设置的单位是扇区(Sector)一般一个扇区是512字节所以16384
对应的是16384 × 512字节 = 8M字节。例如设置/dev/sdb设备
# /sbin/blockdev --setra 16384 /dev/sdb
通过如下命令来获取/dev/sdb设备的read-ahead
# /sbin/blockdev --getra /dev/sdb
16384
设置IO调度方式为deadline。例如
# for i in /sys/block/sd*/queue/scheduler;do echo deadline > $i;done
版权所有Esena(陈淼 ) 编写陈淼 - 386 -
Greenplum Database 管理员指南 V6.2.1
修改操作系统的最大打开文件数和最大进程数。例如
# sed -e s/^ulimit/#ulimit/ -i /etc/profile
# sed -e /^[^#]/d -e /^[[:space:]]*$/d -i /etc/security/limits.conf
# echo '' >> /etc/security/limits.conf
# echo '* soft nofile 1048576' >> /etc/security/limits.conf
# echo '* hard nofile 1048576' >> /etc/security/limits.conf
# echo '* soft nproc
1048576' >> /etc/security/limits.conf
# echo '* hard nproc
1048576' >> /etc/security/limits.conf
# nprocname="/etc/security/limits.d/90-nproc.conf"
# if [ -f "/etc/security/limits.d/20-nproc.conf" ];then
#
nprocname="/etc/security/limits.d/20-nproc.conf"
# fi
# if [ -f $nprocname ];then
#
sed -e /^[^#]/d -e /^[[:space:]]*$/d -i $nprocname
#
echo '' >> $nprocname
#
echo '*
soft nproc
1048576' >> $nprocname
#
echo 'root soft nproc
1048576' >> $nprocname
# fi
注意这里的修改方法是编者一直在使用的方法与官方文档不一致如果希望完全使
用官方文档的设置请参考官方文档的相关内容。
开启core文件并设置到特定的目录位置。例如
# grep core_pattern /etc/sysctl.conf
kernel.core_pattern = /var/core/core.%h.%u.%e.%p.%t
# grep core /etc/security/limits.conf
* soft core unlimited
操作系统内存参数配置
Linux的两个sysctl参数vm.overcommit_memory
vm.overcommit_ratio控制着内存的分配方案。
GP数据库要求设置vm.overcommit_memory2。对于overcommit的三种选择
012对应了不同的行为0允许适度的超限申请内存1允许无节制的超限申请
内存2禁止超限申请内存。为什么GP要求配置为2因为对于01两种情况
都有可能会触发oom-killer一旦触发该行为将无法确保数据库主服务进程一定不
版权所有Esena(陈淼 ) 编写陈淼 - 387 -
Greenplum Database 管理员指南 V6.2.1
会被选中成为被kill的进程那将是十分危险的。
vm.overcommit_ratio影响的是操作系统对于可用内存的计算编者一般将这
个值设置为95意思是说操作系统的可用内存是SWAP + RAM × 95%。这么做并不
已定不安全真正严格控制GP数据库使用内存的参数应该依靠GP数据库的GUC参数
gp_vmem_protect_limit(在开启资源队列时)或者
gp_resource_group_memory_limit(在开启资源组时)来控制将操作系统可用
内存设置的很大主要是为了保障发生Instance切换时的内存可用量避免操作系统
出现OOM报错。例如
# grep overcommit /etc/sysctl.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 95
要禁用hugepage特性。主机的内存分配的控制应该由GP数据库来统一管理。例如
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
共享内存设置
GP数据库需要使用共享内存来满足同一PostgreSQL实例的不同postgres进程
之间的通信。在sysctl.conf文件中编者一直使用如下的设置
kernel.shmmax = 5000000000000
kernel.shmmni = 32768
kernel.shmall = 40000000000
注意与官方建议的值相比编者已经把这些参数做了放大目的是为了支持同一台物
理机上可以部署更多的Primary以满足不同的需求场景。
每个主机上的 Primary 数量
每个主机上运行多少个Primary这的确没有一个通用的公式可以使用虽然没
有一个通用的计算公式但是有一点是明确的不同数量的Primary对数据库集群的
运行性能有很大的影响。每个主机上运行的Primary数量不宜过多也不宜过少
这需要通过主机的资源情况来综合判断很少有文章明确的涉及这个问题的细节编者
版权所有Esena(陈淼 ) 编写陈淼 - 388 -
Greenplum Database 管理员指南 V6.2.1
在此尝试多说一些。
影响每个主机上适合运行多少个Primary的因素包括
CPU Core的数量。这是一个关键因素。一般来说对于生产环境一个Primary
至少要有48Core否则数据库集群的并发批处理能力将会很差。
主机上的可用物理内存的尺寸。早在十年前内存还比较小的时候GP的一体机
基本上是按照一个Primary 8GB的物理内存来配置这从GUC参数
gp_vmem_protect_limit的缺省值(8192)就可以了解到然而十年过去了
不仅单条内存的容量和单机支持的最大内存容量在快速增长数据量也在快速增长
所以目前的情况来看编者建议每个Primary至少要有32GB左右的可用内存
所以目前推荐的单台主机的内存配置最少是256GB
内部互联网络的带宽。官方文档说的是网络端口的数量编者认为这样说不准确
比如单台主机上配置一个40Gb的网络端口换做1Gb的网络端口需要40个才能
得到理论上等价的网络带宽。编者建议每个计算主机至少配置210Gb的网络
端口并使用mode 4bound确保有20Gb的内部互联网络的带宽对于集群规
模超过100台的集群编者建议可以为Master配置410Gb的网络端口以提升
MasterPrimary之间的交互能力。编者认为网络带宽并不直接影响Primary
的数量而是影响磁盘的IO能力是否会被网络拖累。
是否会在GP的计算主机上运行其他应用。编者建议GP的设备要专用一定要避
免与其他应用的混用如果确有必要请联系专业技术支持人员进行具体的评估
以确定如何混合安装GP数据库集群。
基于这些因素就目前主流的2U X86服务器来说假如配置为12GB Cache
支持Raid 5Raid2410K SAS机械盘做成2Raid 5210Gb网络端口使
mode 4bound64CPU Core(开启超线程)256GB512GB的内存建议在
生产环境配置416Primary。配置4Primary将拥有更好的并发能力配置16
Primary将拥有更好的单任务处理能力但并发能力相对较差。当然也可以配置
更多的Primary只是不太适合用于生产环境。
Instance 的内存配置
对于开启资源队列的情况通过GUC参数gp_vmem_protect_limit来限制每个
Instance可以使用的内存总量的最大值。如果某个SQL导致了Instance的总内存使
用量超过了限制会导致该查询失败这种情况下没有什么特别好的办法要么降低
并发要么降低每个查询的内存配额如果GUC参数gp_vmem_protect_limit设置
已经与主机的物理内存相匹配绝对不能随意增加该参数的值那样会导致操作系统报
OOM的错误GUC参数gp_vmem_protect_limit并不是一个需要经常被调整的参
版权所有Esena(陈淼 ) 编写陈淼 - 389 -
Greenplum Database 管理员指南 V6.2.1
只要第一次进行了正确的设置之后只要集群的规模和物理内存配置没有发生调
原则上不需要进行修改。
编者建议GUC参数gp_vmem_protect_limit的值按照如下公式计算即可
gp_vmem_protect_limit = 物理内存 × 90% ÷ 主机上Primary数量
编者不喜欢解释不清的花里胡哨的公式按照编者的体系方案可以确保数据库良
好高效的运行。
在开启资源组的情况下GUC参数gp_resource_group_memory_limit来控
制每个Instance可以使用的内存总量的最大值。
语句的内存配置
语句的内存使用量一般通过statement_mem来限制。或者在开启资源组的情况
(通过gpconfig配置gp_resource_managergroup来开启)如果GUC参数(
者资源组的属性)memory_spill_ratio的值不为0的情况下语句的分配内存由资源
组根据内存配额最大活动事务数和memory_spill_ratio参数的值来决定详情可
以参见"算子内存配额"章节。或者通过资源队列的MEMORY_LIMIT属性和
ACTIVE_STATEMENTS属性来控制语句的内存使用量。
一般可以通过如下的公式来计算statement_mem的值
(gp_vmem_protect_limit × 0.9) ÷ 最大并发查询的数量
例如最大的并发查询的数量为40gp_vmem_protect_limit的值为8192(8GB)
(8192 MB × 0.9) ÷ 40 ≈ 184 MB
语句的内存使用量限制是由statement_mem限制还是由资源组限制或者由
资源队列限制这取决于资源管理方案的设置不过当对内存的需求超过了可分配的
限制就需要将数据溢出到文件系统中如果溢出到文件不能满足要求(通过溢出到文
件的方式不能满足内存不足的需求)查询就会失败。
当语句的内存使用限制受到statement_mem限制时原则上语句的内存使用上
限不能超过statement_mem的限制当然Orca优化器在有些场景会根据需要自动
突破这个参数的限制。
当语句的内存使用限制受到资源队列的限制时语句的内存使用上限一般为
版权所有Esena(陈淼 ) 编写陈淼 - 390 -
Greenplum Database 管理员指南 V6.2.1
MEMORY_LIMIT ÷ ACTIVE_STATEMENTS
注意一般不建议将MEMORY_LIMIT属性和MAX_COST属性结合使用因为执行计划对
Cost的评估误差很大会导致内存的分配完全失去基本的合理性。
要安全的增加statement_mem的值需要确保gp_vmem_protect_limit的值
足够大或者适当的降低并发查询的数量。不过这句话的意思并不是建议盲目的增
gp_vmem_protect_limit参数的值前面已经介绍过这个参数的值不能随意增
大。
注意编者认为statement_memgp_vmem_protect_limit参数和最大并发查
询的数量这两个参数之间并没有严格的等式关系并不是说statement_mem的值一
定不能超过[(gp_vmem_protect_limit × 0.9) ÷ 最大并发查询的数量]计算的
结果因为很多时候内存的真实使用量并不大。根据编者的经验可以通过持续多
日的对系统资源进行统计确定系统的最高活跃内存百分比比如statement_mem
使用的是缺省的125MB的情况下统计发现系统的最高活跃内存百分比为30%那么
statement_mem设置为125MB3倍是安全的用真实的数据来推导出一个合理的
总是比通过公式计算出的结果更实用。
溢出文件的配置
如果分配给语句的内存不足以保证其完全在内存中完成计算则需要将数据文件
溢出到文件系统以缓存中间计算结果。缺省情况下一个查询在一个Primary上的溢
出文件的个数不能超过100000这对于绝大部分的查询来说都是足够的或者说
如果超出了这个限制那应该是查询本身的问题而不是参数设置的问题。
可以通过控制GUC参数gp_workfile_limit_files_per_query的值来控制
一个查询在一个Primary上的溢出文件的个数如果设置为0就意味着对溢出文件的
数量不做任何的限制不过限制溢出文件的数量可以防止劣质的查询对系统造成破
坏性影响。编者建议不要修改这个参数或者如果要改就改小一些以阻止更多
的劣质查询对系统的影响。
如果内存严重不足或者语句的计算出现严重的倾斜则查询可能会导致溢出文件
的数量超出限制此时数据库会返回一个报错信息
ERROR: number of workfiles per query limit exceeded
注意最好不要尝试增加gp_workfile_limit_files_per_query参数的值。如果
遇到了溢出文件数量超过限制的报错首先应该考虑如何优化SQL检查倾斜。可能修
改内存参数也有助于缓解然而100000个文件数都超过了的话可能需要非常大的
内存尺寸才能满足要求。
版权所有Esena(陈淼 ) 编写陈淼 - 391 -
Greenplum Database 管理员指南 V6.2.1
gp_toolkit模式中包含了一些和溢出文件信息相关的视图通过这些视图
可以查看当前系统中正在执行的SQL使用到的溢出文件的情况。这些信息将有助于排查
可能的问题
gp_workfile_entries视图每行记录展示了查询的每个操作在每个
Primary上的溢出文件的使用情况。
gp_workfile_usage_per_query视图每行记录展示了每个查询在每个
Primary上的溢出文件的使用情况。
gp_workfile_usage_per_segment视图每行记录展示了每个Primary
的总的溢出文件的使用情况。
这些视图的信息对于排查当前系统的运行是否良好很有帮助。
GUC参数gp_workfile_compression用于控制溢出文件是否进行压缩存储
6之前的版本类似的参数为gp_workfile_compress_algorithm一般配置为
zlib6版本中gp_workfile_compression是一个布尔型的参数一般建议配
置为on。缺省情况下溢出文件是不压缩的编者建议压缩。
模式设计
GP数据库是一个MPP数据库与共享的单机数据库相比有很大的不同。对于非
范式模型GP数据库将会表现出更好的性能。比如星型模型和雪花模型数据库中的
数据将以大数据量的事实表和小数据量的维表来进行存储。
数据类型
使用一致的数据类型
不同的表之间有关联关系的字段采用相同的字段类型。如果关联的字段之间
字段的数据类型是不同的数据库在进行关联计算时必须将数据进行动态的类型转换
以适配不同类型的关联计算所以对于需要关联的字段来说可能需要适当的调整数
据类型比如增加数据类型的尺寸以适配其他表中需要关联的字段的数据类型对于
变长数据类型来说数据类型定义上的尺寸增加并不会导致数据存储空间的上升。
版权所有Esena(陈淼 ) 编写陈淼 - 392 -
Greenplum Database 管理员指南 V6.2.1
使用合适的数据类型
对于定长数据类型来说选择合适的数据类型避免数据类型过大可以节省存储
空间和提升计算性能。比如通常建议使用变长类型VARCHARTEXT而不是使用定
长类型CHAR虽然这三种数据类型对于相同的数据集合来说并不会有性能差异
TEXTCHAR可能会带来存储尺寸的增加编者认为对于AO表来说不会带来存储
空间的增加。
通常会建议适合使用SMALLINTINT类型时不要使用BIGINT类型这样会节
省存储空间的确如此不过在6版本之前三种整数类型之间的关联查询可能会导致
NESTLOOP或者类型转换的开销所以如果不能确保关联字段之间采用相同的数据类
也许只使用BIGINT比混合使用SMALLINTINTBIGINT更能带来实际的益处
至少可以避免难以预料的类型转换问题。
存储模式
GP数据库为建表语句提供了多种存储选项包括Heap表与AO行存储与
列存储。在使用GP如何正确的选择存储选项极其重要毫不夸张的说这是用
GP的一项基本功如果没理解不同存储选项的优劣随意乱用的话会带来很多的
麻烦这个问题在之前的章节也有多次提到。如何正确的选择Heap表还是AO行存
表还是列存表对于大型的事实表尤为重要对于普通的维表也不能忽视。
关于存储模式的选择的最佳实践包括如下内容
1. 对于需要高并发单条INSERTDELETEUPDATE的场景应该使用Heap表。
2. 对于频繁单条INSERTDELETEUPDATE的场景应该使用Heap表。
3. 对于大型分析型事实表应该采用AO表。
4. 对于大型分区表应该根据分区的适用场景不同的分区采取不同的存储模式。
5. 尽量减少使用列存表。只在特定的场景使用例如事实表的规模很大表中有很
多字段而查询只涉及少数字段行存表无法满足性能要求而列存可以有很大的
性能提升时可以考虑使用列存表。
6. 对于大型事实表应该尽可能的采用压缩存储以节省磁盘空间和提升IO效率。
编者建议Heap表只在类交易型场景使用列存表只在特定的超大表场景使用
一般情况下选择行存压缩AO表作为通用存储模式。
版权所有Esena(陈淼 ) 编写陈淼 - 393 -
Greenplum Database 管理员指南 V6.2.1
Heap表与AO
缺省不指定任何存储模式的情况下(设置了gp_default_storage_options
情况下按照设置的属性作为缺省属性)创建的将是HeapHeap表与所有的
PostgreSQL的表的存储模式相同。对于有交易型并发单条INSERTDELETE
UPDATE的场景以及频繁的单条INSERTDELETEUPDATE的场景应该使用Heap
表。
对于不会频繁修改数据的场景应该使用AO表。对于AO必须避免频繁的单条
INSERTDELETEUPDATE虽然AO表支持并发INSERT但是并发INSERT会导
AO表的数据文件分裂文件数最多会膨胀到128所以不要并发INSERT AO
问题很严重。另外要避免并发DELETEUPDATE AO因为AO表的DELETE
UPDATE操作是EXCLUSIVE并发操作必须排队。
AO表不适合用作频繁修改数据的场景Heap表一样AO表的数据修改(DELETE
UPDATE)只是将数据进行标记并不会真正的被清理掉而且Heap表不同的是
Heap表的无效空间可以通过VACUUM进行重新利用AO表不能重新利用只能进行
数据重新整理类似重建表的操作。所以AO表更适合一次加载很大的数据量且很
少进行修改操作的分析型场景。
行存与列存
行存是传统的存储模式一行记录的所有字段都紧凑的存储在连续的磁盘空间上
这样便于一次读写一整行的记录这是最常见的数据库存储数据记录的方式。
列存是相对于行存而言的GP数据库中列存是将每个字段的数据存储在一个
独立的数据文件中当对列存表进行查询时只需要扫描相关的字段的文件这样
以大大降低IO的消耗。
对于偏交易型的场景建议使用行存表或者更准确的说建议使用Heap
更好的支持频繁的数据更新和插入操作。
对于查询中需要用到很多个字段的场景应该使用行存表对于用于多种工作负载
的表也应该使用行存表因为列存表的适用场景较少主要用于只对少数字段进行分
析查询的场景。
列存表对于查询来说当只查询少数字段时因为只扫描相关字段的数据文件
会带来性能的提升但是对于INSERTUPDATE操作并不会带来性能的提升
为所有字段的数据文件都必须进行读写。所以仅当业务场景的特点满足一定条件时才
适合使用列存表首先是数据量要很大其次数据很少发生变化或者数据的变
化都是批量操作表的字段较多但是分析查询时只涉及少数字段。
列存因为同一个字段的数据连续存储在一个独立的文件中所以数据具有更强
的相似性与行存相比当采用相同压缩选项时列存的压缩效果会更好从而可以节
版权所有Esena(陈淼 ) 编写陈淼 - 394 -
Greenplum Database 管理员指南 V6.2.1
省磁盘存储空间。但是这不应该成为选择列存的主要理由不该使用列存的场景
能因为可以更节省磁盘存储空间而强行使用列存。
对于列存和行存相比如果都读取全部的字段并进行全表扫描列存会消耗更
多的计算资源。
注意编者提醒如果使用行存可以满足业务的性能需求建议不要使用列存。
注意编者反复强调不要随意使用列存的主要原因是列存的一个最大的问题就是文
件数量容易失控这与目前GP使用的列存实现方式有关编者认为如果使用类似
Parquet格式的方式来实现列存就不用过于担心文件数量失控的问题。
压缩
GPAO表提供了多种压缩选项使用压缩选项可以节省磁盘存储空间改善系
统的IO效率可以根据适用场景在不同的分区选择不同的压缩属性。
注意添加分区表时新增的分区的压缩属性不会自动继承上层的压缩属性(虽然曾经
有些版本是继承的)必须在增加分区时明确指定压缩属性所以养成新增分区时写
WITH子句的习惯很重要或者设置好gp_default_storage_options参数。
编者建议6版本之前选择36级的ZLIB压缩作为通用压缩属性6版本开
选择16级的ZSTD压缩作为通用压缩属性其他压缩算法和压缩级别可以作为
扩展知识进行学习和了解但是编者认为没有实用性。比如1ZSTD压缩性能极好
甚至有些时候压缩效率未必比其他级别有显著的差距。虽然编者介绍了压缩算法和级
别的最佳选择范围在实际使用中如有必要仍然可以通过测试来找到最适合项目场
景的压缩属性。
注意永远不要在压缩文件系统上使用压缩表。
分布键
在使用GP数据库时正确的选择分布键非常重要分布键要确保数据分布的均
因为MPP数据库中查询的总时间由执行最慢的Instance决定所以整个
集群的速度等于最慢的Instance的速度。当数据分布存在倾斜的情况下存储数据量
更大的Instance将需要花费更多的时间来完成计算因此所有的Instance应该存
储均衡的数据量并且执行均衡的计算量。如果个别Instance存储的数据量远远超过
版权所有Esena(陈淼 ) 编写陈淼 - 395 -
Greenplum Database 管理员指南 V6.2.1
其他Instance不仅会导致计算性能差还可能会导致OOM类的报错。不过OOM
不一定是数据倾斜导致的数据倾斜只是一种可能。
在选择分布键时需要考虑以下因素
对任何表明确指定分布键或者使用随机分布而不是依赖缺省的行为。
只要有可能应该只使用一个字段作为分布键而不是使用组合字段作为分布键。
如果不是为了特定的目的设计不要为分析型用途的表选择WHERE条件包含的字
段作为分布键。比如查询是主键查询使用主键作为分布键并不会有任何不妥
反而是最合适的设计这一条主要表达的意思是不要让个别Instance来承担一
个大的查询任务。
应该尽可能的避免使用日期或者时间字段来作为分布键。因为一般不会使用这种
字段来与其他的表进行关联查询。
不要用分区字段作为分布键。因为一般不会使用这种字段来与其他的表进行关联
查询。
为了改善大表之间的关联性能应该考虑将大表之间关联的字段作为分布键。注意
这里说的是大表之间的关联但凡涉及与小表关联的场景完全不应该作为选择分
布键的考虑因素。
分布键字段应该使用唯一性较高的字段。虽然主键往往是唯一性最好的字段
不建议为了选择一个分布键而去增加一个主键这是一种逻辑颠倒的做法
应该选择一个常用于大表之间关联的某个唯一性较高的字段作为分布键一般
这个字段可能在其他某个表中具有主键特征例如客户ID例如会员卡号
如手机号码例如身份证号码等等。
如果没有某个字段适合单独作为分布键就需要考虑组合分布键是否对关联查询有
帮助如果有帮助应该选择字段数量最少的可能性一般建议永远不要超过两个
字段。
只有当关联条件包含全部的分布键字段时分布键才能对关联有帮助否则必须
进行数据的重分布所以如果实在没有合适的单个字段或者两个字段用作分布键
也许RANDOMLY分布会是一个不错的选择。过多的字段用作分布键除了带来计算
分布键HASH值时更多的资源消耗一般并不会带来其他好处。
要定期或者不定期的检查数据分布的倾斜情况。可以参考"数据的分布与倾斜"
节获得更多关于数据倾斜的信息。
随机分布并不能绝对的保证每个Instance上的数据数量完全相同或者误差在数
条以内但可以绝对的保证数据的相对均衡。官方文档说差异会小于10%编者不清
版权所有Esena(陈淼 ) 编写陈淼 - 396 -
Greenplum Database 管理员指南 V6.2.1
楚这个数字是怎么来的根据编者的经验对于数据量较大的表来说RANDOMLY分布
Instance之间的记录数差异极小远小于10%编者认为10%可能是最坏的情况。
优秀的分布策略对于大表与大表的关联至关重要对于GP来说要执行表与
表的关联相关的记录必须在同一个Instance如果相关的记录不在同一个
Instance在执行查询的过程中必须在Instance之间进行动态的数据重分
当然有些时候还可能会是广播操作。重分布是将所有的数据根据关联字段重新
计算HASH值并确定数据重新分发到其他Instance而广播是将表中的所有数据在
每个Instance上分发一份完整的拷贝。
选择重分布还是选择广播这是优化器基于两张表的规模进行的Cost评估对一
张表进行重分布的代价是
单个Instance的记录数 × gp_segments_for_planner × 每行的字节数
对一张表进行广播的代价是
单个Instance的记录数 × gp_segments_for_planner2 × 每行的字节数
优化器会评估哪种选择的代价更低以决定选择重分布或者广播。
本地关联
使用合适的分布键使得数据均衡的分布在所有Instance并使得表之间的关
联可以实现本地关联可以显著的提升关联查询的性能。当关联查询涉及的记录都位于
相同的Instance上时关联操作可以在Instance本地完成而不需要在所有
Instance之间进行数据重分布操作这样大大节省了数据移动的代价避免了进行
大量的网络数据传输。
当关联的表之间无法实现本地关联(关联的字段不能全部包含分布键字段)
必须在执行计划中加入数据移动(motion)的步骤(Slice)例如(Redistribute
motion)(Broadcast motion)这样执行计划会变得更复杂而且从磁盘读
取的到内存的数据副本需要通过网络层在所有Primary之间进行数据重分布
要消耗大量的网络资源虽然从理论上来说如果从磁盘读出的数据都能够及时的发
送出去重分布的影响会很小但是实际上网络带宽往往都是有限的虽然使用了
万兆网络但相比于磁盘的性能和压缩率来说还是完全不占优势而且有些时候
表中的数据还可能来自系统缓存所以如果可以避免或者减少数据移动对关联查询
会带来非常显著的性能提升。
版权所有Esena(陈淼 ) 编写陈淼 - 397 -
Greenplum Database 管理员指南 V6.2.1
数据倾斜
数据倾斜往往会导致极其严重的性能问题甚至导致OOM类的报错。数据倾斜
不仅仅影响数据扫描操作的性能对于很多执行计划中的算子来说也会导致性能问题。
这与执行计划有关比如很多时候Table Scan的下一步操作是Motion算子
可能是一个合理的重分布数据之后就变的均衡就不会影响后续算子的计算性能
而如果Table Scan的下一步是Hash算子然后是Hash Agg算子那么这些算子
在严重倾斜的Primary都会因为需要计算的数据量远远多于其他Primary而严重
影响查询的整体性能。
在完成大量数据装载之后对数据表进行倾斜检查显得尤为重要在日常的运维和
管理工作中也应该定期的对数据表进行倾斜检查。可以参考"数据的分布与倾斜"
节获得更多关于数据倾斜的信息。
下面是官方文档中示例的检查一张表的记录数的最大值、最小值以及差异性的例子
SELECT 'Example Table' AS "Table Name",
max(c) AS "Max Seg Rows", min(c) AS "Min Seg Rows",
(max(c)-min(c))*100.0/max(c) AS "Skew Ratio"
FROM (SELECT count(*) c, gp_segment_id FROM facts GROUP BY 2) AS a;
这个SQL有分母为0的风险而且编者并不喜欢这种方法这种方法需要对被检
查的表进行全表扫描这是一种简单而粗暴的方式也是性能最差的方式如果需要对
大量的表进行倾斜检查性能和时效方面都是无法接受的。编者在"数据的分布与倾斜
"章节介绍了目前最先进的检查数据倾斜的方案。
编者已经介绍了最先进的检查数据倾斜的方案所以gp_toolkit模式中的关于
数据倾斜的视图编者不再介绍有兴趣的可以自行研究一下无异于count(*)
计算倾斜
倾斜可能会有多种表现比如从整体的磁盘使用量分布来看从每张数据表的尺
寸分布来看从计算过程来看。对于管理人员来说应该定期对磁盘使用量的分布和数
据表尺寸的分布进行监控及时发现数据倾斜现象计算过程的倾斜一般比较难以在
运行之外的时间被发现往往需要实时的介入。
倾斜往往是数据库的性能和稳定性问题的根源这不是危言耸听这是无数的血
淋淋的教训的总结。对于数据分布的倾斜通过检查表中数据的分布情况就很容易发现
版权所有Esena(陈淼 ) 编写陈淼 - 398 -
Greenplum Database 管理员指南 V6.2.1
也很容易处理一般是因为没有指定分布键或者选择了错误的分布键只需要重新
选择一个合适的分布键即可完美解决。
然而当倾斜发生在关联、排序、聚合等各种算子的计算过程中时事情就变的十
分复杂这种情况我们称之为计算倾斜。而要处理计算倾斜可以说十分困难一般的
技术人员很难发现更不用说解决这种问题但这也是用好GP非常关键的一门武功
此门绝技练到第十层应该可以算得上初级宗师了吧实际上在社区中很多知名的
人物未必能够在处理计算倾斜时做到驾轻就熟信手拈来可见此门武功门槛极高。
几乎很少有介绍计算倾斜的文档和文章因为这很难讲解下面举个简单的例子来
介绍一下计算倾斜以及如何解决。先来创建一张测试表并填充示例数据
CREATE TABLE skew
(
a integer
)
WITH (APPENDONLY=true, COMPRESSLEVEL=1, COMPRESSTYPE=zstd)
DISTRIBUTED RANDOMLY;;
INSERT INTO skew SELECT round(random()*3);
ANALYZE skew;
INSERT INTO skew SELECT round(random()*3) FROM generate_series(1,999999);
INSERT INTO skew SELECT round(random()*3) FROM skew,generate_series(1,99);
测试版本为6.9.0版本集群规模为72Primary通过上述的SQL可以得知
统计信息是失真的(为了演示故意为之当然实际生产中也极有可能会出现这种情况
或者有时候也无法绝对避免这种情况)因为分布策略是RANDOMLY数据分布是均
衡的但是字段aDISTINCT数量分别是3这个数量相对于Primary的数量太小
了。先来看一下缺省情况下下面这个SQL的执行计划
select count(*) from (
select a,count(*) from skew group by 1
) x;
文字版的执行计划为
图形化的执行计划为
版权所有Esena(陈淼 ) 编写陈淼 - 399 -

 

 

 

 

 

 

 

Content      ..     6      7      8      9     ..