|
|
Greenplum Database 管理员指南 V6.2.1
性限制,这个让编者有点难以接受,期待该功能的改进。
基于角色的资源组会从逻辑上根据 CONCURRENCY 属性划分等量的槽位,同时会
为这些槽位配额相同百分比的内存资源,如果 MEMORY_LIMIT 属性为 0,内存资源的
管理方式将与资源队列的方式相同(很多时候,这也是资源队列升级到资源组的最平滑
的过渡方式)。
基于角色的资源组 CONCURRENCY 属性的缺省值为 20。
在资源组中并发事务数量,达到并发事务数限制(CONCURRENCY)后,任何提交的
事务都将排队,当正在执行的事务完成之后,在有充足内存资源的情况下,数据库将开
始执行最早排队的事务。
可以通过设置 GUC 参数 gp_resource_group_bypass 为 TRUE 绕过资源组的
并发事务限制,不过,通过这种方式提交的事务,其资源是受限的,而且仍有可能会因
为资源不足而失败。编者认为,资源受限并不是什么大事,最麻烦的是,需要修改 SQL,
增加参数的设置,才能使用这个特性。
可以设置 gp_resource_group_queuing_timeout 参数来指定事务排队的时
间长度,超时之后,数据库将 cancel 该事务,该参数缺省值为 0,意思是排队时间长
度没有限制,编者认为,这个参数可能一般也不会用到,因为编者想不出在生产环境中,
什么情况下,需要把排队的事务因等待时长的原因而自动 cancel 掉。
CPU 配额
通过 CPU_RATE_LIMIT 来配置资源组可用的 CPU 资源的百分比,使用 CPUSET
来配置资源组专用的 CPU Core 的序号,二者是不同的 CPU 资源的配额模式。配置资
源组时,必须选择其中一种,只有需要特殊保护 CPU 资源的极高优先级的资源组需要
考虑 CPUSET 方式的 CPU 资源配额。
GP 允许在不同的资源组中同时使用这两种 CPU 配额模式,也可以在使用过程中随
时修改 CPU 的配额模式,当发现某类优先级极高的业务,其 CPU 资源会受到其他资源
组的影响而产生波动时,可以尝试将其 CPU 配额模式修改为 CPUSET。
参数 gp_resource_group_cpu_limit 用于配置每个主机上最大分配给 GP
Instance 的 CPU 资源的百分比。不管使用哪种 CPU 配额模式,该参数都控制着所有
资源组的最大 CPU 使用率。其余的资源需要留给操作系统和数据库的主服务进程使用。
参数 gp_resource_group_cpu_limit 的缺省值为 0.9(90%)。
注意:如果在 GP 集群的主机上还有其他程序,gp_resource_group_cpu_limit
版权所有:Esena(陈淼 ) 编写:陈淼 - 50 -
Greenplum Database 管理员指南 V6.2.1
的缺省值是没有为其他程序预留 CPU 资源的,如果要为其他程序保留 CPU 资源,可能
需要调整该参数。
注意:应该尽量避免将 gp_resource_group_cpu_limit 设置为大于 0.9,这样可
能会导致 GP 工作负载抢占所有的 CPU 资源,从而影响数据库的主服务进程获取不到足
够的 CPU 资源。
按照 Core 来配额 CPU
使用 CPUSET 属性来指定哪些 CPU 的 Core 为资源组专用,被指定的 Core 必须
是在系统中存在的,且不能已经分配给其他资源组,虽然 GP 将这些 Core 指定为该资
源组专用,但操作系统中的其他非 GP 数据库的进程仍然可以使用这些 CPU Core(再
次说明,设备专用的重要性)。
使用 CPUSET 时,需要使用单引号引起来一串以逗号分隔的 Core 序号或者序号范
围。例如:'1,3-5'。
将 CPU 的 Core 分配给 CPUSET 型的资源组时,需要考虑以下因素:
使用CPUSET型的资源组时,指定的Core是被资源组独占的,即便该资源组中没有
正在执行的事务,这些CPU Core仍处于空闲状态,不会被其他资源组使用,所以,
应该尽可能的避免设置过多的Core数量,避免系统的CPU资源浪费。
不要分配0号Core,0号Core需要保留以备不时之需:
缺省资源组admin_group和default_group至少需要一个Core,当把所有
的Core都指定为其他资源组专用时,缺省的资源组就只能使用0号Core,此
时,admin_group和default_group将与占用了0号Core的资源组共用0
号Core。
当使用一个新的机器来替换现有集群中的一个机器,而新的机器的CPU Core
的数量减少了,就没有足够的Core来满足CPUSET的配置,数据库将会把0号
Core分配给这些资源组以避免启动失败。
将CPU Core分配给资源组时,应该尽量使用数字小的序号。否则,当更换一个CPU
Core的数量变少的机器时,或者将数据库备份并恢复到一个CPU Core的数量变
少的集群时,资源组的创建可能会失败,因为在新的机器上数字大的Core序号可
能不存在。
通过 CPUSET 配置的资源组,在 CPU 资源的使用上有更高的优先级,其最高的 CPU
版权所有:Esena(陈淼 ) 编写:陈淼 - 51 -
Greenplum Database 管理员指南 V6.2.1
使用率是分配的 Core 数量占节点全部 Core 数量的百分比。
在使用 CPUSET 配置资源组时,将不能设置 CPU_RATE_LIMIT 属性,会被自动设
置为-1,这两个属性不能同时配置,只能二选一。
按照百分比来配额 CPU
对于 GP 集群中的每个机器来说,CPU 资源是可以按照百分比进行均分的,通过
CPU_RATE_LIMIT 属性来配置的资源组,系统将会为其配额指定百分比的 CPU 资源。
在设置 CPU_RATE_LIMIT 参数时,可设置的最小值是 1,最大值是 100,同时,系统
中所有资源组的 CPU 百分比的总和不能超过 100。
通过 CPU_RATE_LIMIT 属性设置的所有资源组的 CPU 资源配额的总和受限于:
被 CPUSET 独占剩余的 CPU Core 的数量 ÷ 机器上 CPU Core 的总数 × 100 ×
gp_resource_group_cpu_limit 参数的值 = CPU_RATE_LIMIT 资源组可利用的
系统 CPU 资源的总百分比。CPUSET 型的资源组,CPU 资源百分比也需要从总数中扣
除,只不过,资源的配额,采用的是固定 CPU Core 的方式来实现,目的是避免与其
他资源组的争抢。
通过 CPU_RATE_LIMIT 配置的资源组,其可以使用的 CPU 资源是弹性的,不是
固定的,数据库可能会将空闲的资源组的 CPU 资源分配给其他繁忙的资源组使用,不
过,一旦被划走 CPU 资源的资源组开始有事务执行,CPU 资源将会重新分配回去,需
要注意的是,CPUSET 型的资源组,即便没有事务在执行,其 CPU 资源也不会被其他
资源组划走。对于有多个资源组在繁忙的情况,他们将按照 CPU_RATE_LIMIT 配置的
值,按照比例获取空闲资源组的 CPU 资源,例如,CPU_RATE_LIMIT 设置为 40 的资
源组获得的 CPU 资源将是 CPU_RATE_LIMIT 设置为 20 的资源组的 2 倍。
在使用 CPUSET 配置资源组时,将不能设置 CPU_RATE_LIMIT 属性,会被自动设
置为-1,这两个属性不能同时配置,只能二选一。
内存配额
启用资源组之后,内存的使用可以在 GP 数据库的 Host、Instance 和资源组层
面来管理和控制,还可以通过资源组在事务层面来控制。
参数 gp_resource_group_memory_limit 设置了每个 GP Host 主机上可以
版权所有:Esena(陈淼 ) 编写:陈淼 - 52 -
Greenplum Database 管理员指南 V6.2.1
分配给资源组的系统内存的最大百分比。gp_resource_group_memory_limit 的
缺省值为 0.7(70%)。
GP 数据库在 Host 主机上的可用内存在 Primary 之间平均分配,当启用资源组来
管理资源时,分配给每个 Instance 的内存是,Host 的总可用内存 ×
gp_resource_group_memory_limit ÷ Host 主机上的 Primary 总数,可通过
下面的公式计算得出:
rg_perseg_mem = ((RAM × (vm.overcommit_ratio ÷ 100) + SWAP) ×
gp_resource_group_memory_limit) ÷ num_of_active_primary
其中[RAM × (vm.overcommit_ratio ÷ 100) + SWAP]为 Linux 可用内存
的计算方式。
每个资源组都可以配置一定百分比的专享内存,在创建资源组时通过
MEMORY_LIMIT 属性来配置,MEMORY_LIMIT 属性的最小取值为 0,最大取值为 100。
当设置 MEMORY_LIMIT 为 0 时,GP 将不会为该资源组配置专享内存,而是使用全局
共享内存来满足该资源组中的内存需求。可以参见"全局共享内存"章节。
注意:GP 数据库中所有资源组的 MEMORY_LIMIT 总和,不能超过 100.
基于 ROLE 的内存配额的更多配置
对于基于 ROLE 的内存配额来说,为资源组配置的专享内存(MEMORY_LIMIT 不为
0)将会继续分为定额部分和可共享部分。创建资源组时,MEMORY_SHARED_QUOTA 属
性用于指定,为资源组配额的专享内存中,多少百分比作为可共享内存,这部分的可共
享内存,该资源组中的并发事务都可以使用,并且采用先到先得的原则来分配,正在运
行的事务可能完全不用,也可能用一些,也可能使用到全部。
MEMORY_SHARED_QUOTA 属性的取值范围是 0 到 100,缺省值是 80。
正如之前说的,CONCURRENCY 属性控制着资源组中最大的并发事务数量,如果为
资源组配置了专享内存(MEMORY_LIMIT 不为 0),定额部分的内存将按照最大并发事
务数量来平均分配,每个槽位将获得完全相同的份额,也就是说,即便没有并发事务在
执行,这部分定额内存也是保留的。
版权所有:Esena(陈淼 ) 编写:陈淼 - 53 -
Greenplum Database 管理员指南 V6.2.1
此图展示的是内存配额的情况,该图与官方文档中有不同,因为 default_group
资源组的 memory_limit 是 0,应该是只能使用全局共享内存的资源。
当一个查询的内存消耗超过了资源组中定额部分的限制,将可以从该资源组的可共
享部分获取,因此,对于一个事务槽位来说,可以获得的最大内存使用量,是每个槽位
的专享定额部分 + 可共享部分总量。不过,当有全局共享内存时,资源组的可共享部
分用完之后,还可以从全局共享内存获得内存资源。
全局共享内存
为所有资源组(包括缺省的 admin_group 和 default_group)配置的
MEMORY_LIMIT 属性的总和,是数据库为这些资源组预留的专享配额。如果总和小于
100,剩余部分就会作为全局共享内存来管理。全局共享内存,只有使用了 vmtracker
内存管理模式(基于 ROLE 的资源组)的资源组可以使用。
如果可以的话,数据库会在为查询分配了资源组的定额部分的内存和可共享部分
(如果有的话)的内存之后,为事务分配全局共享内存。这部分内存的分配也是按照先
到先得的原则。
注意:数据库会统计(但不主动监测)资源组中事务的内存使用情况,如果资源组中的
事务使用内存的情况达到了以下所有条件,该事务将会失败:
资源组中可共享部分的内存耗尽。
全局共享内存耗尽。
版权所有:Esena(陈淼 ) 编写:陈淼 - 54 -
Greenplum Database 管理员指南 V6.2.1
事务请求更多的内存。
当预留了一些全局共享内存(例如 10%到 20%)时,数据库通过资源组来管理内存
使用将会更有效。全局共享内存会有助于降低大量内存消耗型查询出现异常的概率。
算子内存配额
大多数的算子(我们将执行计划中的 Hash,Sort,Join,Agg 等运算操作统一
称为算子)都不是内存密集型的算子,也就是说,在执行过程中,数据库分配的内存足
够其使用。有些内存密集型的算子,例如,Join 和 Sort,如果内存中放不下大量的
数据,数据就需要溢出到磁盘上。
参数 gp_resgroup_memory_policy 用于控制一个查询中所有算子的内存分
配策略,对于资源组,目前支持 eager_free(缺省值)和 auto 两种内存策略。当设
置为 auto 策略时,数据库的资源组内存管理,将会为非内存密集型算子分配固定尺寸
的内存,剩余的内存分给内存密集型算子。当设置为 eager_free 策略时,内存资源
的分配会更优化,数据库会将已经完成的算子释放的内存重新分配给后续的算子。
MEMORY_SPILL_RATIO 属性用于设置,在一个事务中,分配给该事务的内存的相
对百分比,这个比较难描述,请参考下面的算式来理解。当达到该限制时,该事务将会
产生溢出文件到磁盘上。数据库会根据 MEMORY_SPILL_RATIO 的设置来确定分配给
一个事务的内存尺寸,在 EXPLAIN ANALYZE 中显示的 Memory used 是 Master 上
分配的内存值。计算公式为:
int(
SYS_MEM
× gp_resource_group_memory_limit
÷ num_of_active_primary
× MEMORY_LIMIT ÷ 100
÷ CONCURRENCY
× MEMORY_SPILL_RATIO ÷ 100
)
注意:内存分配的最小单位与SYS_MEM × gp_resource_group_memory_limit ÷
num_of_active_primary的结果是否大于16GB有关,如果其大于16GB,则会一直
除以2并将最小单位(起始值为1MB)乘以2。比如计算结果得到33GB,则,最小单位为
4MB。
实际上,是将操作系统可用内存,乘以 GP 可用内存百分比,乘以资源组的内存配
额比例,除以并发事务限制数量,除以当前主机上 Primary 的数量,得到的是当前事
务所在资源组,平均到每个并发事务的内存尺寸,MEMORY_SPILL_RATIO 限制的是
这个尺寸的百分比使用量。
版权所有:Esena(陈淼 ) 编写:陈淼 - 55 -
Greenplum Database 管理员指南 V6.2.1
例如:
SYS_MEM = 5537MB
gp_resource_group_memory_limit = 0.7
num_of_active_primary = 3
MEMORY_LIMIT = 10
CONCURRENCY = 10
MEMORY_SPILL_RATIO = 10
带入公式求得,初始分配给该事务的内存为 1MB。计算所得的结果甚至可能会出
现 0MB 的情况,如果是 0MB,则需要从可共享内存和全局共享内存获得内存,未必会
出现溢出文件,如果不为 0MB,而实际需要的内存大于分配的值,则需要溢出文件,
所以,1MB 可能会产生 workfile,而 0MB 可能不会产生 workfile。
MEMORY_SPILL_RATIO 属性的取值范围是 0 到 100,缺省值是 0。当
MEMORY_SPILL_RATIO 属性的值为 0 时,数据库将根据 statement_mem 参数的值
来确定初始分配给一个事务的内存尺寸,一旦按照 statement_mem 参数的值来确定
内存的初始化分配尺寸,超过 statement_mem 参数限制的内存需求,将需要溢出到
磁盘。在 MEMORY_SPILL_RATIO 属性不为 0 时,超过初始分配尺寸的内存需求,需
要通过产生溢出文件来实现。
注意:当设置 MEMORY_LIMIT 属性为 0 时,MEMORY_SPILL_RATIO 属性也必须设置
为 0。
在 SESSION 中,还可以通过设置 memory_spill_ratio 参数的值来设置当前事
务的 MEMORY_SPILL_RATIO 属性。
官方文档上说,对于低内存消耗型的查询来说,设置如下的参数可以提升查询的性
能,编者觉得,有待验证,至少,编者认为,这种操作可能没有特别显著的性能提升。
=# SET memory_spill_ratio=0;
=# SET statement_mem='10 MB';
使用专享内存还是使用全局共享内存
如果没有为资源组配额专享内存(MEMORY_LIMIT 和 MEMORY_SPILL_RATIO 属
性被设置为 0),将会产生如下影响:
版权所有:Esena(陈淼 ) 编写:陈淼 - 56 -
Greenplum Database 管理员指南 V6.2.1
全局共享内存的尺寸会增加。
资源组的功能将会与资源队列相似,通过statement_mem参数的值来确定初始分
配给一个事务的内存尺寸。
该资源组中的事务将与其他资源组中的事务竞争全局共享内存,并且采用先到先得
的原则来分配。
数据库无法保证一定能为该资源组中的事务分配到内存。
当同时有多个事务需要从全局共享内存获取配额时,该资源组中的查询出现内存不
足的风险增加。
要降低重要资源组中查询出现内存不足的风险,可以考虑为该资源组配置一些专享
内存,这样做会降低全局共享内存的尺寸,但为了降低该资源组出现内存不足的风险,
这是一种权衡的选择。
其他内存事项
基于 ROLE 的资源组会管理所有通过 palloc()函数分配的内存,通过 linux 的
malloc()函数分配的内存将不会被资源组管理。因此,为了确保基于 ROLE 的资源组
能够准确的管理内存的使用情况,应该避免在自定义函数中使用 malloc()函数来分
配大量内存。
配置与使用资源组
注意:在RedHat6或者CentOS6中使用资源组是有问题的,这是因为早期的cgroup
有缺陷,最好将Kernel升级到2.6.32-696或者更高的版本以修复已知的问题,从而
可以更好的使用资源组功能。这些问题在Redhat7或者CentOS7中已经修复。
环境要求
版权所有:Esena(陈淼 ) 编写:陈淼 - 57 -
Greenplum Database 管理员指南 V6.2.1
GP 数据库,使用 Linux 的 cgroup 来管理资源组的 CPU 资源,同时,使用 cgroup
来管理基于外部组件的资源组的内存资源。通过 cgroup,GP 数据库将数据库进程的
CPU 资源和外部组件的内存资源与主机上其他进程进行隔离。这就可以将每个资源组
的 CPU 资源和外部组件的内存资源进行限制。
关于 cgroup 的更多信息,可以参考对应 Linux 发行版的 Control Groups 文档。
在 GP 数据库的每个 Host 主机上完成如下 cgroup 的配置(使用编者的一键部署命
令时,除了安装必要的操作系统组件,其他配置工作都会自动完成):
1、 如果是在 SuSE11+操作系统运行 GP 数据库集群,需要将所有 Host 主机启用
swapaccount 内核参数并重启机器,之后才能继续进行 cgroup 的配置。
2、 使用 ROOT 用户或者通过 sudo 权限创建 GP 数据库的 cgroup 配置文件:
$ sudo vi /etc/cgconfig.d/gpdb.conf
3、 在/etc/cgconfig.d/gpdb.conf 配置文件中加入如下配置信息:
group gpdb {
perm {
task {
uid = gpadmin;
gid = gpadmin;
}
admin {
uid = gpadmin;
gid = gpadmin;
}
}
cpu {
}
cpuacct {
}
memory {
}
cpuset {
}
}
这些配置,用于设置由 gpadmin 用户管理 CPU 和 CPU Core 以及内存的控制,
GP 数据库只针对基于外部组件的资源组会使用 cgroup 来管理内存资源。
4、 如果操作系统中没有安装并运行 cgroup 的相关组件,需要在 GP 集群的所有 Host
版权所有:Esena(陈淼 ) 编写:陈淼 - 58 -
Greenplum Database 管理员指南 V6.2.1
主机上进行安装和启用。根据不同的操作系统,这些命令会略有不同,使用 ROOT
用户或者通过 sudo 权限来执行这些命令:
Redhat/CentOS 7.x系统
$ sudo yum install libcgroup-tools
$ sudo cgconfigparser -l /etc/cgconfig.d/gpdb.conf
$ sudo systemctl enable cgconfig.service
Redhat/CentOS 6.x系统
$ sudo yum install libcgroup
$ sudo service cgconfig start
$ sudo chkconfig cgconfig on
SuSE 11+系统
$ sudo zypper install libcgroup-tools
$ sudo cgconfigparser -l /etc/cgconfig.d/gpdb.conf
5、 运行以下命令验证是否正确设置了 GP 数据库 cgroup 配置:
$ CGROUP_MOUNT_POINT=`df -h|grep cgroup|awk '{print $NF}'`
$ if [ "$CGROUP_MOUNT_POINT" != "" ];then
> ls -l $CGROUP_MOUNT_POINT/{cpu,cpuacct,cpuset,memory}/|grep gpdb
> fi
如果输出 4 行 owner 为 gpadmin:gpadmin 的目录,则表明设置成功了。
启用资源组
在安装 GP 时缺省使用资源队列来管理资源。要使用资源组取代资源队列来管理资
源,必须修改参数 gp_resource_manager 为 group。
1、 修改参数 gp_resource_manager 的值为 group:
$ gpconfig -s gp_resource_manager
$ gpconfig -c gp_resource_manager -v "group"
2、 重启 GP 数据库:
版权所有:Esena(陈淼 ) 编写:陈淼 - 59 -
Greenplum Database 管理员指南 V6.2.1
$ psql postgres -c "CHECKPOINT"
$ gpstop -af
$ gpstart -a
启用资源组之后,任何 ROLE 提交的事务都会经过该 ROLE 所属的资源组来执行,
并受到该资源组的限制(并发事务数量、CPU 百分比和内存百分比)。类似的,外部组
件的 CPU 和内存资源也受到分配到该外部组件的资源组的限制。
GP 数据库缺省创建了两个资源组,分别为 admin_group 和 default_group。
一旦启用了资源组,未明确分配资源组的 ROLE,会根据 ROLE 的类型分配一个缺省资
源组,SUPERUSER 会被分配 admin_group,普通 ROLE 会被分配 default_group。
两个缺省资源组的缺省属性如下:
属性(限制类型)
admin_group
default_group
CONCURRENCY
10
20
CPU_RATE_LIMIT
10
30
CPUSET
-1
-1
MEMORY_LIMIT
10
0
MEMORY_SHARED_QUOTA
80
80
MEMORY_SPILL_RATIO
0
0
MEMORY_AUDITOR
vmtracker
vmtracker
需要注意的是,缺省的两个资源组的 CPU_RATE_LIMIT 属性和 MEMORY_LIMIT
属性也计入 Host 主机的总百分比,当创建新的资源组时,可能需要调整这两个缺省资
源组的属性配置。
创建资源组
要创建一个资源组,需要提供资源组的名称以及 CPU 配额模式,还可以配置一些
可选项:最大并发事务数量,内存配额,内存的共享部分占比,内存溢出到文件的阈值。
使用 CREATE RESOURCE GROUP 命令来创建一个新的资源组。
创建资源组时必须指定 CPU_RATE_LIMIT 或者 CPUSET 的值,这用于限制该资源
组可用的 CPU 的百分比。可以指定 MEMORY_LIMIT 为资源组配置专享内存配额的百分
比,如果 MEMORY_LIMIT 设置为 0,GP 将不会为该资源组配置专享内存,而是使用全
局共享内存来满足该资源组中的内存需求。
例如,创建一个名称为 rgroup1 的资源组,CPU 配额为 20,内存配额为 25,内
版权所有:Esena(陈淼 ) 编写:陈淼 - 60 -
Greenplum Database 管理员指南 V6.2.1
存溢出到文件的阈值为 20:
=# CREATE RESOURCE GROUP rgroup1 WITH
(CPU_RATE_LIMIT=20, MEMORY_LIMIT=25,MEMORY_SPILL_RATIO=20);
分配了 rgroup1 资源组的所有 ROLE 将共享 20%的 CPU 配额,类似的,这些 ROLE
也将共享 20%的内存配额。使用缺省的内存管理模式 vmtracker 以及缺省的
CONCURRENCY 为 20。
如果要创建基于外部组件的资源组,除了必须指定 CPU_RATE_LIMIT 或者
CPUSET 的值,还必须设置 MEMORY_LIMIT 的配额,同时还必须设置
MEMORY_AUDITOR 为 cgroup,并且明确的设置 CONCURRENCY 为 0。例如要创建一
个名称为 rgroup_extcomp 的资源组,CPU 配额为 1 Core,内存配额为 15:
=# CREATE RESOURCE GROUP rgroup_extcomp WITH
(MEMORY_AUDITOR=cgroup, CONCURRENCY=0, CPUSET='1', MEMORY_LIMIT=15);
使用 ALTER RESOURCE GROUP 来调整资源组的配额。要修改资源组的配额,需
要为资源组的属性指定一个新的值。例如:
=# ALTER RESOURCE GROUP rg_role_light SET CONCURRENCY 7;
=# ALTER RESOURCE GROUP exec SET MEMORY_SPILL_RATIO 25;
=# ALTER RESOURCE GROUP rgroup1 SET CPUSET '2,4';
注意:不能设置 admin_group 资源组的 CONCURRENCY 属性为 0。
使用 DROP RESOURCE GROUP 命令来删除资源组,要删除一个资源组,该资源组
不能被分配给任何 ROLE,同时,该资源组上不能有任何活动的事务和等待的事务。如
果删除一个基于外部组件的资源组,该资源组上正在运行的实例将会被杀死。例如:
=# DROP RESOURCE GROUP exec;
配置基于内存限制的查询终止
当有全局共享内存时,runaway_detector_activation_percent 参数设置
了全局共享内存的阈值,当全局共享内存达到参数指定的利用率时,将触发资源组中的
查询被终止,这只针对内存管理模式为 vmtracker 的资源组。编者的理解是,当阈
值达到时,那些继续向全局共享内存申请配额的事务将会被终止,其他不需要向全局共
享内存申请配额的事务将不受影响。
版权所有:Esena(陈淼 ) 编写:陈淼 - 61 -
Greenplum Database 管理员指南 V6.2.1
什么时候会有全局共享内存,当系统中所有资源组 MEMORY_LIMIT 属性的值的和
小于 100 时。例如,系统中配置了 3 个资源组,MEMORY_LIMIT 属性的值分别为 10、
20、30,那么全局共享内存为 100 - (10 + 20 + 30) = 40。
分配资源组给 ROLE
在创建了一个 MEMORY_AUDITOR 属性为缺省值 vmtracker 的资源组后,该资源
组就可以分配给 ROLE 了(可以是一个或者多个)。通过 CREATE ROLE 或 ALTER ROLE
命令的 RESOURCE GROUP 子句来分配资源组给 ROLE。如果在 CREATE ROLE 时没有
设置资源组,会根据 ROLE 的类型分配一个缺省资源组,SUPERUSER 会被分配
admin_group,普通 ROLE 会被分配 default_group。
使用 ALTER ROLE 或 CREATE ROLE 命令来分配一个资源组给 ROLE。例如:
=# ALTER ROLE bill RESOURCE GROUP rg_light;
=# CREATE ROLE mary RESOURCE GROUP exec;
可以将一个资源组分配给一个或者多个 ROLE。如果 ROLE 有层级关系,将一个资
源组分配给一个上层的 ROLE,这个设置并不会传递到该组的其他 ROLE,也就是说,
ROLE 的资源组属性不可继承。
注意:不能将创建的基于外部组件的资源组分配给一个 ROLE。
如果想要将一个资源组从一个 ROLE 移除,并按照缺省的规则分配一个缺省资源组,
可以修改 ROLE 并分配一个名为 NONE 的资源组。例如:
=# ALTER ROLE mary RESOURCE GROUP NONE;
监控资源组状态
本章节介绍查看资源组的状态信息的方法。
版权所有:Esena(陈淼 ) 编写:陈淼 - 62 -
Greenplum Database 管理员指南 V6.2.1
查看资源组配额
通过 gp_toolkit.gp_resgroup_config 视图可以查看资源组的配额设置。不
过,编者建议可以重建该视图,原有的视图定义实在不够优雅:
=# CREATE OR REPLACE VIEW gp_toolkit.gp_resgroup_config AS
SELECT groupid,groupname,
vs[1] AS concurrency,
vs[2] AS cpu_rate_limit,
vs[3] AS memory_limit,
vs[4] AS memory_shared_quota,
vs[5] AS memory_spill_ratio,
DECODE(vs[6],null,'vmtracker','0','vmtracker',
'1','cgroup','unknown') AS memory_auditor,
vs[7] AS cpuset
FROM (
SELECT g.oid AS groupid,
g.rsgname AS groupname,
array_agg(c.value order by reslimittype) vs
FROM pg_resgroup g, pg_resgroupcapability c
WHERE g.oid = c.resgroupid
GROUP BY 1,2
) t;
ALTER TABLE gp_toolkit.gp_resgroup_config OWNER TO gpadmin;
GRANT ALL ON TABLE gp_toolkit.gp_resgroup_config TO gpadmin;
GRANT SELECT ON TABLE gp_toolkit.gp_resgroup_config TO public;
查看资源组的配额设置:
=# SELECT * FROM gp_toolkit.gp_resgroup_config;
查看资源组的查询状态和 CPU 内存使用量
通过 gp_toolkit.gp_resgroup_status 视图来查看资源组的事务活跃情况,
版权所有:Esena(陈淼 ) 编写:陈淼 - 63 -
Greenplum Database 管理员指南 V6.2.1
排队情况以及实时的 CPU 和内存的使用量:
=# SELECT * FROM gp_toolkit.gp_resgroup_status;
不过,编者觉得这个视图没法看,CPU 和内存使用量的字段是个很大的 Json,难
以阅读。像下面这样可能会容易阅读一些:
=# SELECT rsgname,groupid,num_running,num_queueing,
num_queued,num_executed,total_queue_duration,
json_each(cpu_usage)::text cpu_usage,
json_each(memory_usage)::text memory_usage
FROM gp_toolkit.gp_resgroup_status
ORDER BY rsgname,cpu_usage;
查看资源组在每个 Host 主机的 CPU 和内存使用量
通过 gp_toolkit.gp_resgroup_status_per_host 视图来查看每个资源组
在每个 Host 主机上的 CPU 和内存的实时使用量:
=# SELECT * FROM gp_toolkit.gp_resgroup_status_per_host;
查看资源组在每个 Instance 的 CPU 和内存使用量
通过 gp_toolkit.gp_resgroup_status_per_segment 视图来查看每个资
源组在每个 Instance 上的 CPU 和内存的实时使用量:
=# SELECT * FROM gp_toolkit.gp_resgroup_status_per_segment;
查看资源组被分配到 ROLE 的情况
版权所有:Esena(陈淼 ) 编写:陈淼 - 64 -
Greenplum Database 管理员指南 V6.2.1
通过关联 pg_roles 和 pg_resgroup 两张系统表来查看资源组被分配到 ROLE
的情况:
=# SELECT rolname, rsgname FROM pg_roles, pg_resgroup
WHERE pg_roles.rolresgroup=pg_resgroup.oid;
查看资源组中正在执行和排队的查询
通过 pg_stat_activity 系统视图来查看资源组中有哪些查询正在执行,或者
正在排队,以及排队的时间等:
=# SELECT query, waiting, rsgname, rsgqueueduration FROM pg_stat_activity;
pg_stat_activity 视图,可以查看执行语句的状态信息,这与 PostgreSQL
相似。如果一个查询使用了外部组件(如 PL/Container),该查询将会有两个部分,
一部分是查询本身在 GP 数据库中运行,而另一部分 UDF 则在 PL/Container 容器中
运行,在 GP 数据库中运行的查询本身由 ROLE 的资源组来管理,在 PL/Container
运行的 UDF 由 PL/Container 的资源组管理,后者在 pg_stat_activity 视图中
无法体现,数据库无法获取 PL/Container 外部组件中的运行情况。
终止资源组中正在运行或者排队的事务
有时,可能需要终止资源组中正在执行的事务或者还在排队的事务。例如想把某个
还在排队的查询移除,或者想把某个已经执行很久的事务中断,亦或是想把某个占用并
发数槽位的 IDLE 事务清除以让给其他 ROLE 使用。
缺省情况下,事务可以无限期的在资源组中排队,如果想要为排队设置超时时间,
可以设置 gp_resource_group_queuing_timeout 参数,该参数指定一个毫秒数,
当事务排队时间超过这个设置时,将会被数据库中断。
要手动终止一个事务,首先要确定该查询相关的进程号(pid),得到了该 pid 之
后,通过调用 pg_cancel_backend()函数来终止该查询。
例如,通过如下语句查看所有资源组中正在执行和排队的语句,如果查询没有结果,
说明资源组中没有正在执行的事务或者排队的事务。
版权所有:Esena(陈淼 ) 编写:陈淼 - 65 -
Greenplum Database 管理员指南 V6.2.1
=# SELECT rolname, g.rsgname, pid, waiting, state, query, datname
FROM pg_roles, gp_toolkit.gp_resgroup_status g, pg_stat_activity
WHERE pg_roles.rolresgroup=g.groupid
AND pg_stat_activity.usename=pg_roles.rolname;
例如,要终止 pid 为 2395 的查询:
=# SELECT pg_cancel_backend(2395);
还可以为 pg_cancel_backend()函数提供一个可选的消息参数,用于通知该查
询的 ROLE,告知为何终止了其执行的事务。例如:
=# SELECT pg_cancel_backend(2395,'因系统维护暂停使用');
该事务的 ROLE 会收到如下信息:
ERROR: canceling statement due to user request: "因系统维护暂停使用"
注意:尽可能避免使用操作系统的KILL命令来杀死GP数据库的任何进程,当然,有时
如果万不得已,在尽量确保安全的情况下,也不是绝对不能使用,但专业技术支持可能
会不支持这种擅自操作导致的严重后果,所以,如有必要,请联系专业技术支持人员。
转移查询的资源组
数据库的 SUPERUSER 可以执行 gp_toolkit.pg_resgroup_move_query()
函数来将一个正在执行的事务转移到另一个资源组,这样,在不中断该查询的情况下,
可以将其转移到一个资源配额更多的资源组。
注意:只能转移一个正在执行的事务,不能转移因为并发事务限制或者内存限制导致排
队和等待的事务,已经在执行的事务,我为什么要转移它,编者认为,更多的可能是需
要转移一个派对和等待的事务,希望这方面可以得到改善。
调用 pg_resgroup_move_query()函数需要提供两个参数,PID 和新的资源组
名称。例如:
=# SELECT gp_toolkit.pg_resgroup_move_query(2514,'default_group');
在调用 pg_resgroup_move_query()函数时,该查询将受到新的资源组的配额
限制:
如果目标资源组的最大并发事务数量已经超了,该查询会进行排队等待状态。
版权所有:Esena(陈淼 ) 编写:陈淼 - 66 -
Greenplum Database 管理员指南 V6.2.1
如果目标资源组的内存资源不足,调用该函数时会收到如下报错信息:
group <group_name> doesn't have enough memory . . .
在这种情况下,可以增加目标资源组的内存配额,或者等有资源空缺时再转移。
转移查询的资源组之后,该查询将与目标资源组中的其他事务竞争资源,因此,无
法保证目标资源组中的事务不受影响,目标资源组中的事务可能会受此影响而导致查询
失败,保留足够的全局共享内存,可能会有效降低这种风险。
pg_resgroup_move_query()函数只是把指定的事务转移到目标资源组中,其
所在 Session 中之后的事务仍然通过原来的资源组执行。
注意:转移查询的资源组,这个功能是 6.8 版本才引入的功能。
如果是从 6.8 之前的版本升级而来,需要手动创建函数来使用该用能:
CREATE FUNCTION gp_toolkit.pg_resgroup_check_move_query(IN session_id
int, IN groupid oid, OUT session_mem int, OUT available_mem int)
RETURNS SETOF record
AS 'gp_resource_group', 'pg_resgroup_check_move_query'
VOLATILE LANGUAGE C;
GRANT EXECUTE ON FUNCTION
gp_toolkit.pg_resgroup_check_move_query(int, oid, OUT int, OUT int)
TO public;
CREATE FUNCTION gp_toolkit.pg_resgroup_move_query(session_id int4,
groupid text)
RETURNS bool
AS 'gp_resource_group', 'pg_resgroup_move_query'
VOLATILE LANGUAGE C;
GRANT EXECUTE ON FUNCTION gp_toolkit.pg_resgroup_move_query(int4,
text) TO public;
如果要将版本降到 6.7 或者更早的 6 版本,可以手动删除这些函数:
DROP FUNCTION gp_toolkit.pg_resgroup_check_move_query(IN int, IN oid,
OUT int, OUT int);
DROP FUNCTION gp_toolkit.pg_resgroup_move_query(int4, text);
版权所有:Esena(陈淼 ) 编写:陈淼 - 67 -
Greenplum Database 管理员指南 V6.2.1
使用资源队列
在出现资源组之前,GP 一直是使用资源队列来管理资源,资源队列最常见的使用
场景就是限制并发查询的数量。资源队列是基于查询语句来做并发控制的,而资源组是
基于事务来做并发控制。所以在资源队列中可能会出现多语句的事务之间的死锁现象,
一边在等资源队列的锁,另一边在等对象的锁,这种情况在资源组中不会出现,因为资
源组是以事务为单位进行排队的。因此,资源队列存在死锁风险,虽然概率很低。
资源队列如何工作
在安装GP时缺省使用资源队列来管理资源。所有的ROLE都必须分配到资源队列。
如果管理员创建ROLE时没有指定资源队列,该ROLE将会被分配到缺省的资源队列
pg_default。
建议管理员为不同类型工作负载创建结构性独立的资源队列。例如,可以为高级用
户、WEB用户、报表管理等创建不同的资源队列。可以根据相关工作的负载压力设置合
适的资源队列限制。目前资源队列的限制包括:
活动语句数量。同时正在执行的最大语句数量。这往往是资源队列的唯一用处。
活动语句内存使用量。所有正在执行的语句使用的总内存不能超过该限制。
活动语句优先级。该值设定了该资源队列相对于其他资源队列在CPU资源使用上的
优先级,这里说的优先是相对的。这种优先级,几乎是没用的,MAX和MIN之间可
能也测不出差异,无法达到资源组的CPU压制效果,如果能达到,也就不需要资源
组了。
活动语句的成本限制。该值限制的是,由执行计划评估得到的的Cost值,该值以
涉及的磁盘页(disk page)作为计量单位。
资源队列创建好之后,ROLE(User)可以被分配到合适的资源队列。一个资源队列
可以分配多个ROLE,但每个ROLE只能被分配到一个资源队列。
资源队列如何工作
在数据库运行时,用户提交一个查询,该查询会被数据库根据其所在的资源队列的
资源进行评估。如果评估认为该查询不会超过资源限制,该查询将被立即执行。如果评
估认为该查询超过了资源限制(例如,正在执行的查询语句的数量已经达到了最大活动
语句数的限制),该查询需要等到有足够的资源时才能被执行。查询按照先进先出的方
版权所有:Esena(陈淼 ) 编写:陈淼 - 68 -
Greenplum Database 管理员指南 V6.2.1
式排队。在查询优先级启用的情况下,系统会定期的重新分配计算资源。编者想说,排
队也是要消耗内存的,资源队列的排队相当于是在等待锁,而且查询的执行计划已经生
成并开始执行,只是未获取必要的锁,实际上内存已经分配,如果有大量消耗大量内存
的语句在排队,可能会出现内存不足的报错。
超级用户是不受资源队列限制的。超级用户的查询语句总是被立即执行,不管其所
在的资源队列如何限制。
内存限制如何工作
在资源队列上设置的内存限制使得每个Instance上该资源队列能够使用的内存
总和不能超过设定的最大值。每个查询语句分配的内存大小是资源队列的内存限制除以
最大活动语句数量(建议与活动语句数限制结合使用,而不是与cost限制结合使用,如
果是与cost限制结合使用,将按照cost的权重进行分配)。例如,资源队列的内存限
制为2000MB,活动语句数限制为10,那么每条执行语句可以得到200MB的内存。缺省
的内存分配可以针对每条语句通过设置statement_mem参数来覆盖(最大可以达到资
源队列限制的值)。一旦一条语句开始执行,其分配的内存一直到执行结束才会释放(即
便其实际使用的内存小于分配的内存)。
执行优先级如何工作
资源限制是针对活动语句来说的,内存和成本的限制属于是否许可类型,其决定查
询语句是允许进入查询状态还是保持排队状态。在语句处于活动状态时,其需要分享
CPU资源,这部分的资源由资源队列的优先级控制。当一个更高优先级的语句进入运行
状态时,其要求获得更多的CPU资源,相应的需要减少其他运行中语句的CPU资源。
语句的规模和复杂程度不会影响到CPU资源的分配。例如一个简单低cost的查询
与一个庞大复杂的查询同时执行却有着相同的优先级,他们在同一时间段内将分配到相
同的CPU资源。当一个新的语句开始执行,CPU资源分配的比重需要被重新计算,不过,
相同优先级的语句之间获得的CPU资源仍然是相同的。
版权所有:Esena(陈淼 ) 编写:陈淼 - 69 -
Greenplum Database 管理员指南 V6.2.1
例如,管理员想要创建3个资源队列:adhoc用于做持续查询的业务分析,
reporting用于做定期的报表工作,executive用于高级用户查询。管理员希望确保
定期报表工作不受到adhoc分析查询不可预测的资源消耗的影响,希望高级用户提交的
查询能够获得更多计算资源。因此,资源队列优先级可以设置为这样:
adhoc -- Low priority
reporting -- High priority
executive -- Maximum priority
运行时,CPU资源由正在运行语句的优先级决定如何分配。如果语句1与语句2来自
reporting队列且同时运行,他们将获得相同CPU资源。当一个来自adhoc队列语句
开始运行,其需要较少的CPU资源。CPU资源的分配将做调整,他们之间的比重受他们
的优先级决定:
注意:该图显示的是粗略的百分比。在CPU的使用上,并不总是按照精确的比值来
分配资源,因为资源组做不到CPU资源的精细控制。
当一个来自executive的语句开始执行,CPU资源将根据他们的优先级重新调整。
该语句相对于adhoc和reporting来说可能是很简单的,但在其执行完之前,其仍获
取最大份额的CPU资源。
版权所有:Esena(陈淼 ) 编写:陈淼 - 70 -
Greenplum Database 管理员指南 V6.2.1
资源队列评估的语句类型
并不是所有的SQL语句都被资源队列评估和限制。缺省状态下只有SELECT、
SELECT INTO、CREATE TABLE AS SELECT和DECLARE CURSOR语句被评估和限
制。若将Server端参数resource_select_only设置为off,INSERT、UPDATE和
DELETE语句也将被评估和限制。
使用资源队列做资源管理的步骤
在GP中使用资源队列做资源管理涉及到如下几个任务:
1. 创建资源队列并设置合适的限制。
2. 为User Role指定资源队列。
3. 使用资源队列相关的系统视图监控和管理资源队列。
配置资源队列管理资源
在初始化GP集群时资源管理缺省使用资源队列。缺省的资源队列是pg_default,
活动语句数量限制为20,成本(Cost)无限制,内存(Memory)无限制,中(Medium)
优先级。建议为不同类型的工作负载,创建不同类型的资源队列。
版权所有:Esena(陈淼 ) 编写:陈淼 - 71 -
Greenplum Database 管理员指南 V6.2.1
配置资源队列
1.
以下为一般的资源队列相关的GUC配置参数:
max_resource_queues -- 设置最多可以有多少个资源队列。
max_resource_portals_per_transaction -- 设置每个事务最多可以打
开几个游标(Cursor)。值得注意的是每个游标需要占用资源队列的一个活动查询。
resource_select_only -- 若设置为on,SELECT、SELECT INTO、CREATE
TABLE AS SELECT和DECLARE CURSOR语句被评估限制。若设置为off,INSERT、
UPDATE和DELETE语句也将被评估和限制。
resource_cleanup_gangs_on_wait -- 在开始一个新的查询之前先清空所
在资源队列中其他空闲的工作进程。
stats_queue_level -- 打开资源队列使用信息收集,这样就可以通过查询系
统视图pg_stat_resqueues查看资源队列的使用情况。
2.
以下参数与内存使用有关:
gp_resqueue_memory_policy -- 设置GP内存管理模式。设置为none的情况
下内存管理与4.1版本之前相同。设置为auto的情况下,内存受statement_mem
和资源队列内存限制的控制。缺省为eager_free,这种模式下内存的管理和分
配会更高效,并不是说这种模式下内存就不受statement_mem和资源队列的限制,
执行计划会分为很多个算子,当设置为eager_free时,在每个算子执行结束之
后,会尽快回收那些分配给已经结束的算子的内存并分配给之后的算子。
statement_mem与max_statement_mem -- 用于为每个活动语句分配内存
(可以复写资源队列的缺省值)。max_statement_mem由SUPERUSER设置,应考
虑避免普通用户的超负荷使用。在任何时候statement_mem都必须小于
max_statement_mem。
gp_vmem_protect_limit -- 限制每个Instance上所有语句可以使用的内存
总量的上限值。导致内存使用超过该上限的语句会被取消(Cancel)从而导致得不
到执行。该参数要根据具体硬件情况进行合理的评估,从OS层面来说,物理内存
的容量用完之后,根据OS的配置,可能会使用SWAP,对于普通磁盘来说,不到万
不得已,强烈建议不要使用SWAP。
gp_vmem_idle_resource_timeout 与
gp_vmem_protect_segworker_cache_limit -- 用于释放Instance上空
闲DB进程的内存。为了提高并发量,管理员可以考虑调整这些配置。一般不需要
修改这些参数。
版权所有:Esena(陈淼 ) 编写:陈淼 - 72 -
Greenplum Database 管理员指南 V6.2.1
3. 以下参数与查询优先级有关。注意,这些参数都是本地化(LOCAL)的参数,必须
修改所有Instance的postgresql.conf文件:
gp_resqueue_priority -- 查询优先级特性是否启用,缺省值为ON,如果GUC
参数gp_resource_manager的值为group,则gp_resqueue_priority的值
将显示为OFF。
gp_resqueue_priority_sweeper_interval -- 设置CPU为所有活动语句
重新计算CPU资源分配的时间间隔。缺省值通常已经可以满足要求。
gp_resqueue_priority_cpucores_per_segment -- 设置每个Instance
使用的CPU core的数量。缺省情况下Instance为4而Master为24。该参数是
LOCAL参数。该参数对于Master也是有影响的,需要配置一个较高的值。例如,
在一个集群中,每个Host主机有8个CPU Core并且每个Instance Host有4个
Instance,那可以按照如下配置:
Master:
gp_resqueue_priority_cpucores_per_segment = 8
Instance:
gp_resqueue_priority_cpucores_per_segment = 2
提示:官方文档中会提到:如果每个Instance Host主机上配置的Instance数量低
于CPU核数,确保将该参数调整到一个合适的值,过低的值可能会导致CPU资源利用不
足。编者认为,实际上,往往可能不需要过于关注这个问题。
4. 要查看和修改这些参数,尽可能使用gpconfig命令来统一修改,很少有人直接去
改postgresql.conf文件,不过如果由于参数修改不当导致GP系统无法启动,
可能需要手动修改或者进入Master Only模式进行gpconfig配置。
5. 例如,要查看一个参数的配置情况:
$ gpconfig -s gp_vmem_protect_limit
在 SQL 中使用 show 命令也可以查看一个参数的值,但其不能体现 Master 与
Instance 之间的差异,仅显示 Master 的值。
6. 例如,要修改一个参数的值,且Master的值与Instance不同:
$ gpconfig -c gp_resqueue_priority_cpucores_per_segment -v 2 -m 8
7. 重启GP以确保修改的参数生效(本节介绍的参数都需要重启生效):
$ psql -d postgres -c 'CHECKPOINT'
$ gpstop -af
版权所有:Esena(陈淼 ) 编写:陈淼 - 73 -
Greenplum Database 管理员指南 V6.2.1
$ gpstart -a
创建资源队列
创建资源队列涉及到Name、cost、最大活动语句数量、执行优先级等。通过CREATE
RESOURCE QUEUE命令来创建新的资源队列。
创建含活动语句数量限制的资源队列
资源队列通过设置ACTIVE_STATEMENTS控制最大活动语句数量。例如,创建一
个名称为adhoc,最大活动语句数量为3的资源队列:
=# CREATE RESOURCE QUEUE adhoc WITH (ACTIVE_STATEMENTS=3);
这意味着,分配到adhoc资源队列的所有ROLE,在同一时刻最多只能有3个语句处
于执行状态。如果该队列当前已经有3个语句正在执行,在该队列的ROLE提交第4个语
句时,其将处于等待状态,直到前面3个语句有一个执行完成。
创建含内存限制的资源队列
资源队列通过设置MEMORY_LIMIT控制该队列所有语句可以使用的内存总量。每
个主机上所有Primary可以获得的物理内存总和不得超过该主机的物理内存总量。建
议将MEMORY_LIMIT控制在该Primary可以获得的物理内存总数的90%以下。例如,
一个Host主机有512GB的物理内存,配置有6个Primary,那么每个Primary可以获
得的物理内存为85GB。这样就可以简单的得到MEMORY_LIMIT=0.9*85GB=76GB。如
果存在多个资源队列,他们的MEMORY_LIMIT的总和应被控制在不超过76GB。
当与ACTIVE_STATEMENTS结合使用时,缺省每个语句获得的内存为:
MEMORY_LIMIT / ACTIVE_STATEMENTS。当与MAX_COST结合使用时,缺省的内存
分配为:MEMORY_LIMIT * (query_cost / MAX_COST)。推荐与
ACTIVE_STATEMENTS结合使用而不是与MAX_COST结合使用,因为cost的评估很多
时候会严重失准,这样将会严重影响内存分配的合理性。
版权所有:Esena(陈淼 ) 编写:陈淼 - 74 -
Greenplum Database 管理员指南 V6.2.1
例如,创建一个活动语句数量为10,内存限制为2000MB的资源队列(每个语句在
执行时在每个Primary上将获得200MB的内存):
=# CREATE RESOURCE QUEUE myqueue WITH (ACTIVE_STATEMENTS=10,
MEMORY_LIMIT='2000MB');
缺省的内存分配可以在每个语句通过设置statement_mem参数覆盖,但不可超过
MEMORY_LIMIT和max_statement_mem设定的值。例如,分配更多的内存:
=> SET statement_mem='2GB';
=> SELECT * FROM my_big_table WHERE column='value' ORDER BY id;
=> RESET statement_mem;
通常来说,对于MEMORY_LIMIT的设置,建议所有的资源队列的总和不要超过
Primary可以获得的物理内存总量,但这个建议未必真的完全合理。如果不同类型语
句之间交错执行,可能真实的使用量会远小于资源队列限制的总量,所以,并不能简单
的说,MEMORY_LIMIT的总和绝对不能超过Primary可以获得的物理内存总量,这取
决于如何安排和优化并行作业,编者提醒,如果某个Primary超出了内存限制超,相
关语句会被取消而导致失败,所以,如何更合理的配置内存参数,以真实生产环境的多
日统计结果为依据来进行调整,最为稳妥。
创建包含成本限制的资源队列
资源队列通过设置MAX_COST限制被执行的语句可消耗的最大成本(Cost)。Cost
以一个浮点数(如100.0或使用科学计数法如1e+2)来指定。
Cost是查询优化器(如使用EXPLAIN查看)评估出来的总预估成本。因此管理员在
设置时需要对该系统执行的查询很熟悉才可以得到一个恰当的Cost阈值。Cost意味着
对磁盘的操作数量。1.0等于获取一个磁盘页(disk page)。
例如,创建一个Cost阈值为100000.0 (1e+5),名称为webuser的资源队列:
=# CREATE RESOURCE QUEUE webuser WITH (MAX_COST=100000.0);
或者
=# CREATE RESOURCE QUEUE webuser WITH (MAX_COST=1e+5);
这意味着,分配到webuser资源队列的所有ROLE执行的全部语句Cost总和不能超
版权所有:Esena(陈淼 ) 编写:陈淼 - 75 -
Greenplum Database 管理员指南 V6.2.1
过100000.0的限制。例如,有20个Cost为5000.0的语句正在执行,第21个Cost为
1000.0的语句提交后只能等到空闲的Cost足够时才能得到执行。
允许在系统空闲时执行语句
若一个资源队列配置了Cost阈值,管理员可以设置允许COST_OVERCOMMIT(缺省
设置是FALSE,经过编者实际测试,与官方文档说的TRUE恰好相反)。在系统没有其他
语句执行时,超过资源队列Cost阈值的语句可以被执行。而当有其他语句在执行时,
Cost阈值仍被强制评估和限制。如果COST_OVERCOMMIT被设置为FALSE,超过Cost
阈值的语句将永远被拒绝。这个特性听起来很不错,可是仔细想一想,没有其他语句在
执行的时间肯定是极少的。
允许小查询绕过队列限制
可能存在一些工作负载很小的查询,管理员希望其不占用资源队列的活动语句数量
而直接被允许执行。例如,一些检索系统表的语句不涉及大的资源消耗甚至不需要与
Instance进行交互。管理员可以设置MIN_COST指明低于指定的开销被认为是小查询。
那些低于MIN_COST的语句将立即被执行。MIN_COST不仅可以同MAX_COST一起使用,
还可以和活动语句数量一起使用。例如:
=# CREATE RESOURCE QUEUE adhoc WITH (ACTIVE_STATEMENTS=10, MIN_COST=100.0);
设置优先级级别
为了控制CPU资源的使用,管理员可以设置合适的优先级。在并发争抢CPU资源时,
高优先级资源队列中的语句将可以获得比低优先级资源队列中的语句更多的CPU资源。
优先级可以在CREATE RESOURCE QUEUE和ALTER RESOURCE QUEUE的时候通
过WITH子句来设置和修改。例如,为adhoc和reporting队列指定优先级,管理员可
以使用下面的命令:
=# ALTER RESOURCE QUEUE adhoc WITH (PRIORITY=LOW);
=# ALTER RESOURCE QUEUE reporting WITH (PRIORITY=HIGH);
创建最高优先级的资源队列executive,管理员可以使用下面的命令:
=# CREATE RESOURCE QUEUE executive WITH (ACTIVE_STATEMENTS=3, PRIORITY=MAX);
在查询优先级特性开启时,资源队列的优先级缺省为MEDIUM。如果关闭(GUC参数
版权所有:Esena(陈淼 ) 编写:陈淼 - 76 -
Greenplum Database 管理员指南 V6.2.1
gp_resqueue_priority的值为OFF或者FALSE),则不会对优先级的设置进行评估,
也就是说,无论什么优先级,大家没有高低之分,一起公平的争抢CPU资源。
重要提示:要使得资源队列的优先级设置在执行语句中强制生效,必须确保优先级特性
的相关参数已经设置好。
分配 ROLE(User)到资源队列
一旦资源队列被创建好了,就需要把ROLE(User)分配到合适的资源队列。如果
ROLE没有被明确的分配到一个资源队列,其将被分配到缺省的资源队列pg_default。
缺省的资源队列有20个活动语句数量限制和MEDIUM的优先级。
使用ALTER ROLE或者CREATE ROLE命令来分配ROLE到资源队列。例如:
=# ALTER ROLE name RESOURCE QUEUE queue_name;
=# CREATE ROLE name WITH LOGIN RESOURCE QUEUE queue_name;
每个ROLE同一时间只能被分配到一个资源队列,可以使用ALTER ROLE命令修改
ROLE的资源队列。
资源队列的分配必须通过逐个User的方式进行。如果有一个层级较高的ROLE(例
如GROUP ROLE),将该ROLE分配到一个资源队列并不会将其包含的User分配到该资
源队列,也就是说,ROLE的资源队列属性,不具有可继承的性质。
SUPERUSER总是不受资源队列的限制。SUPERUSER的查询总是可以立即得到执行,
而不管资源队列的限制如何设置。
从资源队列中移除 ROLE
所有ROLE都需要分配到资源队列。如果没有被明确分配到指定的资源队列,该
ROLE将会进入缺省资源队列pg_default。如果想将ROLE从现有资源队列中移除并放
到缺省队列中,可将其资源队列分配到none。例如:
=# ALTER ROLE role_name RESOURCE QUEUE none;
版权所有:Esena(陈淼 ) 编写:陈淼 - 77 -
Greenplum Database 管理员指南 V6.2.1
修改资源队列
在创建资源队列后,可以使用ALTER RESOURCE QUEUE命令来改变或者重置队列
的限制。还可以使用DROP RESOURCE QUEUE命令删除资源队列。
变更资源队列
使用ALTER RESOURCE QUEUE命令来改变资源队列的限制。一个资源队列必须包
含ACTIVE_STATEMENTS或者MAX_COST(或者都包含)。变更资源队列,设置新的参
数值。例如:
=# ALTER RESOURCE QUEUE adhoc WITH (ACTIVE_STATEMENTS=5);
=# ALTER RESOURCE QUEUE exec WITH (MAX_COST=100000.0);
要将活动语句数量或者内存限制重置为无限制,可以使用-1值。要重置Cost阈值
为无限制,可以设置为-1值。例如:
=# ALTER RESOURCE QUEUE adhoc WITH (MAX_COST=-1.0, MEMORY_LIMIT='2GB');
可以使用ALTER RESOURCE QUEUE命令改变查询优先级。例如,设置一个资源队
列的优先级为最低级别:
=# ALTER RESOURCE QUEUE webuser WITH (PRIORITY=MIN);
删除资源队列
使用DROP RESOURCE QUEUE命令删除资源队列。要删除一个资源队列,该资源
队列不能与任何ROLE相关联,或者队列中有语句正等待执行。删除一个资源队列:
=# DROP RESOURCE QUEUE name;
版权所有:Esena(陈淼 ) 编写:陈淼 - 78 -
Greenplum Database 管理员指南 V6.2.1
检查资源队列状态
检查资源队列状态涉及以下内容:
查看排队语句和资源队列状态
查看资源队列统计信息
查看分配到资源队列的ROLE
查看资源队列中等待的语句
清除资源队列中等待的语句
查看活动语句的优先级
重置活动语句的优先级
查看排队语句和资源队列状态
管理员可以通过查看视图gp_toolkit.gp_resqueue_status来查看资源队列
的状态。该视图展示系统中每个资源队列有多少个语句在等待执行,多少语句正在执行。
查看资源队列在系统中当前的状态:
=# SELECT * FROM gp_toolkit.gp_resqueue_status;
查看资源队列统计信息
如果要追踪资源队列的统计信息和性能,需要为资源队列开启统计信息收集的配置。
这可以通过配置Master上postgresql.conf文件的这个参数来实现(修改参数请使
用gpconfig命令):
stats_queue_level = on
版权所有:Esena(陈淼 ) 编写:陈淼 - 79 -
Greenplum Database 管理员指南 V6.2.1
一旦该配置开启,就可以使用系统视图pg_stat_resqueues来查看资源队列使
用的统计信息。注意,开启该配置会带来轻微的资源开销,每个通过资源队列被执行的
语句都会被追踪。开启统计信息收集对于初期的资源队列诊断是有帮助的,而后期的运
行应该关闭该参数。
查看分配到资源队列的 ROLE
要查看ROLE与资源队列之间的关联关系,可以使用系统视图pg_roles和
gp_toolkit.gp_resqueue_status来获得:
=# SELECT rolname, rsqname FROM pg_roles, gp_toolkit.gp_resqueue_status
WHERE pg_roles.rolresqueue=gp_toolkit.gp_resqueue_status.queueid;
或者可以创建一个视图来简化以后的视图。例如:
=# CREATE VIEW role2queue AS
SELECT rolname, rsqname FROM pg_roles, pg_resqueue
WHERE pg_roles.rolresqueue=gp_toolkit.gp_resqueue_status.queueid;
这样就可以直接查询视图了:
=# SELECT * FROM role2queue;
查看资源队列中等待的语句
当语句通过资源队列执行时,其会被记录在pg_locks系统表中。这里可以查看到
所有的活动语句和等待语句。要检查处于等待状态的语句,可以使用
gp_toolkit.gp_locks_on_resqueue视图。例如:
=# SELECT * FROM gp_toolkit.gp_locks_on_resqueue WHERE lorwaiting = TRUE;
若该查询没有结果返回,意味着此时没有语句在资源队列中等待执行。
版权所有:Esena(陈淼 ) 编写:陈淼 - 80 -
Greenplum Database 管理员指南 V6.2.1
清除资源队列中等待的语句
有时候可能需要清除资源队列中处于等待状态的语句。例如,想要清除在资源队列
中处于等待状态还没有得到执行的语句,也有可能想要终止一个已经开始而需要很长时
间才能完成的语句,或者该语句处于空闲的事务状态而希望把其占用的资源让给其他需
要的ROLE。要达到这些目的,首先需要知道哪些语句需要被清除,确定该进程的PID,
然后使用pg_cancel_backend函数来终止该进程。
例如,查看当前处于活动状态或者等待状态的语句:
=# SET from_collapse_limit TO 1;
SELECT rolname, rsqname, a.pid, granted, a.query, datname
FROM pg_roles r, gp_toolkit.gp_resqueue_status s, pg_locks l,
pg_stat_activity a
WHERE r.rolresqueue = l.objid AND r.rolname = a.usename
AND l.objid=s.queueid AND a.pid=l.pid;
若没有结果返回,意味着当前没有语句处于资源队列中。例如有两个语句在资源队
列中可能是这种样子的:
根据输出结果确定需要清除语句的进程PID(pid)。通过下面的方式清除语句:
=# SELECT pg_cancel_backend(1855);
注意:尽量不要使用OS的KILL命令。当然也不是完全不可以用,除非有把握确保不会
导致数据库损坏。
查看活动语句的优先级
在gp_toolkit模式中有个视图gp_resq_priority_statement,其包含了所
有正在执行的语句的优先级,会话ID等信息。该视图只能通过gp_toolkit模式访问。
版权所有:Esena(陈淼 ) 编写:陈淼 - 81 -
Greenplum Database 管理员指南 V6.2.1
重置活动语句的优先级
SUPERUSER可以在语句运行期间通过内置函数
gp_adjust_priority(session_id, statement_count, priority)调整优
先级。通过该函数SUPERUSER可以提升或者降低任何语句的优先级。例如:
=# SELECT gp_adjust_priority(752, 24905, 'HIGH');
该函数需要获取语句的SESSION ID和Statement Count两个参数,SUPERUSER
可以通过gp_toolkit.gp_resq_priority_statement视图获得,session_id
和statement_count两个参数分别对应rqpsession和rqpcommand。该函数只对指
定的语句有效,同一个资源队列随后的语句仍然使用其预先设定的优先级。
版权所有:Esena(陈淼 ) 编写:陈淼 - 82 -
Greenplum Database 管理员指南 V6.2.1
第七章:定义数据库对象
本章介绍GP的数据定义语言(DDL)以及如何创建和管理数据库对象。
创建与管理数据库
创建与管理表空间
创建与管理模式
创建与管理表
分区大表
创建与使用序列
在GP中使用索引
创建与管理视图
创建与管理物化视图
创建与管理数据库
一个GP系统可以有多个数据库(Database)。这与一些DBMS不同(例如Oracle),
它们的Instance就是Database。在GP系统中,虽然可以创建多个DB,但是客户端程
序一次只能连接一个DB,而且不可以跨越DB执行查询语句。
关于数据库模版
每个新的数据库都是基于一个模版数据库创建的,这种创建可以理解为模板数据库
的复制,如果基于一个非空的模版数据库来创建,那么该模板数据库中的所有对象和数
据都会一模一样的复制到新创建的数据库中。缺省的数据库模版为template1,在初
始化GP系统初期可以连接到该库,在没有明确指定模版的情况下创建新的数据库将缺
省使用该DB作为模版,除非你希望之后创建的DB包含你所创建的对象,不然的话,不
要在该DB中创建任何对象。
除了template1之外,每个新建的GP系统还包含另外两个模版template0和
postgres,这两个DB是系统内部使用的,最好不要删除或者修改。template0模版
版权所有:Esena(陈淼 ) 编写:陈淼 - 83 -
Greenplum Database 管理员指南 V6.2.1
可以用来创建仅包含标准对象的完全干净的数据库。如果想避免从template1中拷贝
任何的对象,可以考虑使用该模。
注意:在创建新的数据库时,模板数据库上必须没有任何连接,否则创建数据库的操作
将会报错失败。
创建数据库
通过CREATE DATABASE命令来创建一个新的数据库。例如:
=# CREATE DATABASE new_dbname;
要创建一个数据库,必须具备创建数据库的权限或者是SUPERUSER身份。若没有
正确的权限是无法创建数据库的,需要联系GP管理员授予必要的权限或者帮助创建一
个数据库。
还有一个客户端程序createdb可以用来创建数据库。例如,通过命令行终端执行
下面的命令将会在指定的Host为Master的GP集群上创建名为mydatabase的数据库:
$ createdb -h masterhost -p 5432 mydatabase
克隆一个数据库
缺省情况下,创建数据库是通过克隆数据库模版template1的方式完成的。然而
任何的DB都可以作为模版来创建一个新的数据库,因此可以通过指定DB的方式克隆或
者拷贝出一个新的数据库,新的DB包含模版库中的所有对象和数据。例如:
=# CREATE DATABASE new_dbname TEMPLATE old_dbname;
查看数据库列表
在psql客户端程序中,直接使用\l指令查看GP中包含模版书籍库在内的所有
Database的列表。使用其他客户端程序时,可以通过查询pg_database系统表来得
到。例如:
=# SELECT datname from pg_database;
版权所有:Esena(陈淼 ) 编写:陈淼 - 84 -
Greenplum Database 管理员指南 V6.2.1
修改数据库
使用ALTER DATABASE命令来修改Database的属性,例如Owner、Name以及缺
省配置等。必须是该Database的Owner或者SUPERUSER才可以执行这样的操作。下
面的例子演示修改缺省的搜索路径:
=# ALTER DATABASE mydatabase SET search_path TO myschema, public, pg_catalog;
删除数据库
使用DROP DATABASE命令来删除Database。该操作将从系统表中删除该
Database的信息记录,并删除该Database包含的全部磁盘数据。必须是该Database
的Owner或者SUPERUSER才可以执行删除Database操作,其他用户无法删除该
Database,在删除Database时,不能有任何用户连接到该Database,包括当前的
操作用户,因此,可以先连接到template1(或者其他Database),然后再删除需要
删除的Database。例如:
=# \c template1
=# DROP DATABASE mydatabase;
这里同样有一个客户端程序叫做dropdb用以删除Database。例如,通过命令行
终端执行下面的命令将会在指定的Host为Master的GP集群上删除名为mydatabase
的数据库:
$ dropdb -h masterhost -p 5432 mydatabase
警告:删除数据库操作是无法回退的。慎用该操作!
创建与管理表空间
表空间(tablespace)允许Database管理员使用多个文件系统来存储数据库对
象,从而可以决定如何更好的利用他们的物理储存设备。表空间的存在有具体的意义,
例如在访问频度不同的数据库对象上使用不同性能的磁盘,例如,将经常使用的表放在
高性能磁盘的文件系统上(例如SSD固态盘),而将其他表放在普通硬盘的文件系统上。
一个表空间,在GP集群中,对应的是一组分布式的操作系统目录,在每个Instance
上都有一个目录,这些目录的集合,组成了一个表空间,表空间创建成功之后,用户在
使用这些表空间时,不需要再关心这些目录的具体位置,只需要在建表时指定表空间名
版权所有:Esena(陈淼 ) 编写:陈淼 - 85 -
Greenplum Database 管理员指南 V6.2.1
称,或者设置缺省的表空间即可,缺省表空间通过参数default_tablespace来设置。
在6版本之前,表空间还不是一个完全独立的概念,其需要依赖文件空间对象,在
6版本之前的文件空间,实际上也是一组分布式的操作系统目录,在每个Instance上
都有一个目录,这些目录的集合,组成了一个文件空间。这一段看起来和刚刚介绍表空
间的几乎一样,是的,没错,在6版本之前,虽然说表空间是依赖文件空间的,但是,
如果这样来描述表空间也是正确的,为什么一般不这样描述呢,因为,文件空间已经把
这个定义做好了,表空间的目录就是这些文件空间的那些目录的子目录,表空间在文件
空间的目录下建立以<tablespace_id>/<database_id>组成的子目录,不同的数
据库中的对象,用到对应的表空间时,数据文件则存储到对应的子目录。
在6版本中,表空间的概念,在单个Instance上来看,几乎与PostgreSQL完全
一致,当创建一个表空间时,需要为该表空间指定一系列的路径,而这些路径将会通过
软连接的方式关联到Instance工作目录的pg_tblspc目录下,以<tablespace_id>
为名称,其中的目录结构为:GPDB_大版本号_系统表版本号/<database_id>。
这里,还将继续介绍文件空间的内容,实际上,如果使用6之前的版本,很多时候,
我们的客户并不需要为创建文件空间头疼,编者在为各位客户安装初始化GP集群时会
自动创建一个名为gpfs的文件空间,当需要使用表空间时,只需要使用这个文件空间
来创建表空间即可。
创建文件空间
注意:6版本开始,已经不再有文件空间的概念,此处所说的是6版本之前的概念。
要创建文件空间,首先需要在所有相关的GP Host主机上准备好需要的目录。文
件系统位置对于Master和所有的Primary和Mirror来说都是必须的。在准备好了文
件目录之后,使用gpfilespace命令来创建文件空间。只有SUPERUSER才能进行该操
作,一般由gpadmin用户来完成。
注意:GP并不直接知晓文件系统的界限,只是把文件存向指定的目录位置。因此,在
一个逻辑磁盘上定义多个文件空间是没有必要的,因为基于文件空间创建的表空间就是
多个子目录,在一个逻辑磁盘上定义多个文件空间只会增加维护的难度。如果有多个逻
辑磁盘,则需要创建创建多个文件空间,虽然一般不会这样规划磁盘,。
使用gpfilespace创建文件空间
1. 使用gpadmin用户登录到GP系统的Master主机。
$ su - gpadmin
2. 创建一个文件空间的配置文件:
版权所有:Esena(陈淼 ) 编写:陈淼 - 86 -
Greenplum Database 管理员指南 V6.2.1
$ gpfilespace -o gpfilespace_config
3. 将会提示输入一个文件空间的名称,Primary Instance的文件系统位置,
Mirror Instance的文件系统位置,Master的文件系统位置。例如,若每个
Instance Host配置了2个Primary和2个Mirror,将会提示输入5个文件系统
位置(包括Master)。就像这样:
Enter a name for this filespace> fastdisk
primary location 1> /gpfs1/seg1
primary location 2> /gpfs1/seg2
mirror location 1> /gpfs2/mir1
mirror location 2> /gpfs2/mir2
master location> /gpfs1/master
4. 该命令将会输出一个配置文件。请再次检查该文件确保其按照期望的那样反映出了
想要使用的文件系统位置。
5. 再次执行该命令,基于之前生成的配置文件创建文件空间:
$ gpfilespace -c gpfilespace_config
转移临时文件或事务文件的位置
注意:此处所说的是6版本之前的概念。
可以选择将临时文件或事务文件转移到一个特殊的文件空间从而改善 DB 的查询性
能、备份性能、数据读写的性能。
临时文件和事务文件缺省都是存储在每个 Instance(包括 Master、Standby、
Primary 和 Mirror)目录下。只有 SUPERUSER 可以移动该位置。只有 gpfilespace
命令可以修改临时文件和事务文件的位置。
关于临时文件和事务文件
除非另有指明,临时文件和事务文件和用户数据放在一起。缺省的临时文件位置为:
<filespace_directory>/<tablespace_oid>/<database_oid>/pgsql_tmp
使用gpfilespace --movetempfiles命令来修改临时文件的位置。
版权所有:Esena(陈淼 ) 编写:陈淼 - 87 -
Greenplum Database 管理员指南 V6.2.1
关于临时文件和事务文件,需要注意以下几点:
虽然可以使用同一个文件空间存储不同类型文件,但只能为临时文件或者事务文件
指定一个文件空间。
如果文件空间被临时文件使用,该文件空间将不能被删除。
文件空间必须提前被创建好才能使用。
使用 gpfilespace 移动临时文件
1. 确保文件空间存在,且与存储其他用户数据的文件空间不同。
2. 将 GP 系统停掉,保持停机状态。
注意:任何活动的连接都会导致 gpfilespace --movetempfiles 操作的失败。
3. 把 GP 启动为限制模式,确保其他用户无法连接,执行下面的命令:
$ gpfilespace --movetempfilespace filespace_name
注意:临时文件位置在 Instance 中配合共享内存使用,在创建、打开、删除临时文
件时用到。如果查询用到了临时文件,表明当前的可用内存已经无法满足该查询对内存
的需求。很多时候我们宁愿使用临时文件也不选择使用 SWAP 作为内存扩展方案。除非
SWAP 的性能比临时文件目录所在文件系统的性能还要高。
使用 gpfilespace 移动事务文件
1. 确保文件空间存在,且与存储其他用户数据的文件空间不同。
2. 将 GP 系统停掉,保持停机状态。
注意:任何活动的连接都会导致 gpfilespace --movetransfiles 操作的失败。
3. 把 GP 启动为限制模式,确保其他用户无法连接,执行下面的命令:
$ gpfilespace --movetransfilespace filespace_name
注意:事务文件位置在 Instance 中配合共享内存使用,在创建、打开、删除事务文
件时用到。
如果要移动临时文件或事务文件的目录到缺省路径,使用如下命令:
$ gpfilespace --movetempfilespace default
和
版权所有:Esena(陈淼 ) 编写:陈淼 - 88 -
Greenplum Database 管理员指南 V6.2.1
$ gpfilespace --movetransfilespace default
在编者看来,这一块的功能几乎不会有人用到,一般来说,Instance 的工作目
录所在的磁盘,就是整个主机上性能最好的磁盘了。
注意:处所说的是 6 版本的概念。
可以选择将临时文件或事务文件转移到一个特殊的表空间从而改善 DB 的查询性能、
备份性能、数据读写的性能。GP 数据库通过 temp_tablespaces 参数来控制,用于
Hash Agg,Hash Join,排序操作等临时溢出文件的存储位置。这个目录缺省为
<data_dir>/base/pgsql_tmp,这与 6 之前的版本不同,6 之前的版本,这个目录
缺省为:<data_dir>/base/<database_id>/pgsql_tmp。
当使用 CREATE 命令创建临时表和临时表上的索引时,如果没有明确的指定表空
间,temp_tablespaces 所指向的表空间将存储这些对象的数据文件。
使用 temp_tablespaces 时需要注意:
1. 只能为临时文件或事务文件指定一个临时表空间,该表空间还可以用于存储其他数
据对象的表空间。
2. 如果表空间被用作临时表空间,该表空间将不能被删除。
创建表空间
注意:此处所说的是6版本之前的概念。
一旦文件空间创建好了,就可以使用该文件空间定义表空间了。要定义一个表空间,
使用CREATE TABLESPACE命令,例如:
=# CREATE TABLESPACE fastspace FILESPACE gpfs;
表空间必须由SUPERUSER才可以创建,不过在创建好之后可以允许普通的DB
User来使用该表空间。可以将CREATE权限授予相应的用户。例如:
=# GRANT CREATE ON TABLESPACE fastspace TO admin;
注意:此处所说的是6版本的概念。
通过CREATE TABLESPACE来创建表空间。例如:
=# CREATE TABLESPACE fastspace LOCATION '/data/gpfs';
版权所有:Esena(陈淼 ) 编写:陈淼 - 89 -
Greenplum Database 管理员指南 V6.2.1
表空间必须由SUPERUSER才可以创建,不过在创建好之后可以允许普通的DB
User来使用该表空间。可以将CREATE权限授予相应的用户。例如:
=# GRANT CREATE ON TABLESPACE fastspace TO admin;
正如看到的这样,在6版本中的表空间的概念发生了很大的变化,不再需要依赖文
件空间的概念,而是直接在表空间的定义中指定路径的信息,这既带来了便捷,也带来
了困扰,以往,Primary和Mirror的文件空间的路径可能是不同的,而在6版本中,
Primary和Mirror的路径必须相同,因为没有地方可以指定相同Content值的
Primary和Mirror拥有不同的路径信息。当集群中不同的Content之间的路径也不相
同时(实际上只要一台机器多于一个数据目录,肯定就会有不同),则需要使用这样的
语法来完成表空间的定义:
=# CREATE TABLESPACE gpts LOCATION '/data/master_ts'
WITH(content0='/data1/gpts', content1='/data2/gpts');
不管是LOCATION还是WITH中的路径都必须指定绝对路径,而且长度不能超过100
个字符,否则会有问题,如果没有指定WITH,则所有Content的Instance都需要有
LOCATION指定的路径,且gpadmin用户拥有该路径的权限,该目录必须为空目录,建
议LOCATION指定Master的目录,其他的Content目录全部在WITH中列出。不要试图
通过修改pg_tblspc目录下软连接的指向去设置Primary和Mirror指向不同的目录,
因为这样会有一个很大的问题,当出现Primary和Mirror的故障切换时,在做
gprecoverseg全量恢复时,GP数据库并不清楚软连接的目标是不同的,这个软连接
的信息是不会存储在系统表中的,做全量恢复时,只是按照对应Content活着的
Instance的信息去重建。
使用表空间存储 DB 对象
表、索引、甚至整个DB都可以存储在特定的表空间。需要拥有对应的表空间的
CREATE权限的ROLE才可以在该表空间上创建对象。例如,在space1表空间上创建一
张名为foo的表:
=# CREATE TABLE foo(i int) TABLESPACE space1;
或者使用缺省表空间参数default_tablespace来设定:
=# SET default_tablespace = space1;
=# CREATE TABLE foo(i int);
在将default_tablespace设置为一个非空字符串后,其相当于给CREATE
TABLE和CREATE INDEX等命令添加一个TABLESPACE的子句,但却不必明确写出。
版权所有:Esena(陈淼 ) 编写:陈淼 - 90 -
Greenplum Database 管理员指南 V6.2.1
如果一个表空间与DB关联,那么其将存储所有该DB的系统表、临时文件等。此外,
其也是在该DB上创建表、索引等缺省的表空间(除非通过TABLESPACE或者
default_tablespace参数重新指定)。如果DB在创建的时候没有与特定的表空间相
关联,那么该DB与其使用的模版DB使用相同的表空间。
一旦表空间被创建了,将可以被任何有访问权限的用户在任意的DB中使用。
查看现有的表空间和文件空间
每个GP系统都有两个缺省的表空间:pg_global(用以存储全局系统表的数据,
系统保留,不可使用)和pg_default(缺省表空间,存储template1和template0
模版数据库和postgres数据库,也是其他数据库的缺省表空间)。
注意:此处所说的是6版本之前的概念。
在6之前的版本中,这些缺省的表空间使用的是缺省的文件空间pg_system(这是
GP集群在初始化的时候建立的,使用的是Instance的工作目录)。
要获取文件空间的信息,可以通过系统表pg_filespace和
pg_filespace_entry进行关联查询。例如:
=# SELECT fsname AS filespace, fsedbid AS dbid,fselocation AS datadir
FROM pg_filespace f, pg_filespace_entry e
WHERE e.fsefsoid = f.oid ORDER BY filespace,dbid;
可通过上述两个系统表与pg_tablespace关联查看表空间的完整定义。例如:
=# SELECT spcname AS tablespace, fsname AS filespace, fsedbid AS dbid,
fselocation ||
decode(spcname,'pg_default','/base','pg_global','/global','/'||t.oid) AS
datadir
FROM pg_tablespace t, pg_filespace f, pg_filespace_entry e
版权所有:Esena(陈淼 ) 编写:陈淼 - 91 -
Greenplum Database 管理员指南 V6.2.1
WHERE t.spcfsoid = e.fsefsoid AND e.fsefsoid = f.oid
ORDER BY tablespace, dbid;
注意:此处所说的是6版本的概念。
在6版本中,这些缺省的表空间,使用的是系统初始化时指定的Master和
Instance的工作目录。
要获取表空间的信息,可以查询pg_tablespace系统表。例如:
=# SELECT oid,* FROM pg_tablespace;
然后使用gp_tablespace_location()函数来查看具体某个表空间的目录信息。
例如:
=# SELECT * FROM gp_tablespace_location(86891) ORDER BY gp_segment_id;
通过该函数无法查询到缺省表空间pg_global和pg_default的目录信息,不过,
这些信息,可以通过查询gp_segment_configuration系统表的datadir字段来获
取。
版权所有:Esena(陈淼 ) 编写:陈淼 - 92 -
Greenplum Database 管理员指南 V6.2.1
删除表空间和文件空间
在表空间相关的所有对象被删除之前,该表空间是不能被删除的。同样的,对于6
之前的版本来说,在相关的表空间被删除之前,文件空间,也是不能被删除的。
要删除表空间,可通过DROP TABLESPACE命令完成。表空间只能被其Owner和
SUPERUSER删除。
在6版本之前,要删除文件空间,可通过DROP FILESPACE命令完成。只有
SUPERUSER可以删除文件空间。
注意:在6版本之前,如果文件空间被临时文件或者事务文件使用,该文件空间将不能
被删除。在6版本开始,如果表空间被临时文件或者事务文件使用,该表空间将不能被
删除。
创建与管理模式
模式(Schema)是在DB内组织对象的一种逻辑结构。模式可以允许用户在一个DB
内不同的模式之间使用相同Name的对象(例如Table)。
缺省"Public"模式
每个新创建的DB都有一个缺省的模式public。如果没有创建其他的模式,在创建
DB对象时将缺省使用public模式。缺省情况下所有的ROLE(User)都有public模式
下的CREATE和USAGE权限。而在创建其他模式时,需要将该模式授权给相关的
ROLE(User)。
创建模式
使用CREATE SCHEMA命令来创建一个新的模式。例如:
=# CREATE SCHEMA myschema;
要访问某个模式中的对象,可以通过模式名加小数点加对象名来指明对象所属的模
式。例如:
schema.table
版权所有:Esena(陈淼 ) 编写:陈淼 - 93 -
Greenplum Database 管理员指南 V6.2.1
还可以在创建模式的时候将Owner设置为其他ROLE(User)。语法如下:
=# CREATE SCHEMA schemaname AUTHORIZATION username;
模式搜索路径
当需要查询特定模式下的对象时,可以通过明确指定模式名的方式来实现。例如:
=# SELECT * FROM myschema.mytable;
若不想通过指定模式名称的方式来实现,可以通过设置search_path参数来完成。
该参数告诉DB在哪些可用的模式中搜索对象。在不指明模式名称的情况下,搜索路径
(search_path)列表中的第一个模式将成为缺省模式,例如创建对象等操作时,对象
将会自动创建到search_path的第一个模式中。
设置模式搜索路径
search_path用于设置模式的搜索顺序。该参数可以通过ALTER DATABASE命令
修改DB的模式搜索路径。例如:
=# ALTER DATABASE mydatabase SET search_path TO myschema, public, pg_catalog;
还可以通过ALTER ROLE命令修改特定ROLE(User)的模式搜索路径。例如:
=# ALTER ROLE sally SET search_path TO myschema, public, pg_catalog;
设置了模式搜索路径之后,在未明确指明模式名称的情况下访问DB对象,将会按
照search_path列表的顺序依次在相应的Schema中查找对应的Object,直到找到为
止,若在不同的Schema中存在相同Name的Object,DB优先匹配search_path中靠
前的Schema下的Object。
查看当前的模式
有时不确定当前所在的模式或者搜索路径。要查看这些信息,可以通过使用
current_schema()函数或者SHOW命令来查看。例如:
=# SELECT current_schema();
=# SHOW search_path;
版权所有:Esena(陈淼 ) 编写:陈淼 - 94 -
Greenplum Database 管理员指南 V6.2.1
删除模式
使用DROP SCHEMA命令来删除模式。例如:
=# DROP SCHEMA myschema;
缺省状态下,只有空的模式才可以被删除。若想要直接删除模式及相关的所有
Object(Table、Index、Function等)。使用如下命令:
=# DROP SCHEMA myschema CASCADE;
系统模式
下面的这些系统模式在所有的DB中都存在:
pg_catalog模式存储着系统表(System Catalog Table)、内置类型(Type)、
函数(Function)和运算符(Operator)。该模式无论是否在search_path中指
明,都存在search_path中,因为没有这个模式的话,SQL将无法执行,数据库
将无法使用。
information_schema模式由一组标准化视图构成,这些视图用于以标准化的方
法从系统表中查看对象信息,不过,该模式中的很多视图定义复杂且臃肿,当库中
对象较多时,这些视图的性能可能会很差,有时候只需要查询必要的信息时,可以
考虑写SQL重新实现。
pg_toast模式是一个储存大对象的地方(那些超过页面尺寸(page size)的记
录)。该模式仅供GP系统内部使用,通常不建议管理员或者任何用户访问。
pg_bitmapindex视图是一个储存Bitmap Index对象的地方。该模式仅供GP
系统内部使用,通常不建议管理员或者任何用户访问。
pg_aoseg视图是一个储存append-optimized表辅助信息的地方。该模式仅供
GP系统内部使用,通常不建议管理员或者任何用户访问。
gp_toolkit是一个管理用的模式,可以查看和检索系统日志文件和其他的系统
信息。gp_toolkit视图包含一些外部表、视图、函数,可以通过SQL的方式访问
它们。gp_toolkit视图对于所有DB User都是可以访问的。
版权所有:Esena(陈淼 ) 编写:陈淼 - 95 -
Greenplum Database 管理员指南 V6.2.1
创建与管理表
GP中的Table除了数据是分布在不同Instance这点外,和其他关系型数据库的
Table是很类似的。在创建Table时,需要一个额外的SQL语法来指明Table的分布策
略。
创建表
CREATE TABLE命令用于创建一张新的Table和定义其结构。在创建Table时,
通常需要定义如下几个方面的信息:
都有哪些字段(Column)以及对应的数据类型。
Table或者Column的约束(Constraint),其限定了Table或者Column可以储
存什么样的数据。
Table的分布策略,其决定了Table的Data如何被分割存储在GP的各个
Instance上。
Table在Disk上的存储方式。例如压缩、按列存储等选项。
大表的分区策略(Partition Table)。
选择 Column 的数据类型
Column的Data Type决定了其可以储存什么类型的数据值。通常应该考虑使用最
小的空间储存数据,不是为了节省空间,重要的是,要考虑Data Type对数据范围的
约束。例如,使用Character类型储存字符串,Date或者Timestamp储存日期,
Numeric储存数字等,如果用TEXT来存储VARCHAR(32),将会允许任意数据范围,
这样会导致很多异常数据不容易被发现。
对于Character类型来说,CHAR、VARCHAR和TEXT之间不存在性能差异,当然
是在不考虑填补空白导致的储存尺寸增加的情况下。然而在其他的DB系统中,可能
CHAR会表现出最好的性能,但在GP中是不存在这种性能差异的。在多数情况下,应该
选择使用TEXT或者VARCHAR而不是CHAR。
对于Numeric类型来说,应该尽量选择更小的数据类型来存储数据。例如,选择
版权所有:Esena(陈淼 ) 编写:陈淼 - 96 -
Greenplum Database 管理员指南 V6.2.1
BIGINT类型来存储SMALLINT类型范围内的数值,会造成空间的大量浪费。另外,过
于宽泛的类型定义会容许异常的数值,造成隐藏的问题,且不容易被发现,应该选择合
适的类型,当有异常数据尝试插入表中时,会因为类型不匹配而报错。
对于打算用来做Table Join的Column来说,应该考虑选择相同的数据类型。如
果做Join的Column具有相同的数据类型(例如主键Primary Key与外键Foreign
Key),其工作效率会更高。如果两者的数据类型不同,DB还需要将其中一个类型做转
换才可以做关联比较,这种开销是不必要的浪费。
设置 Table 和 Column 的约束
数据类型用来限制在Table中可以存储的数据的性质。但对于很多应用来说,数据
类型提供的限制粒度太大。SQL标准允许在Table和Column上定义约束。约束将允许
在Table的数据上使用更多的限制。如果User试图在Table上储存违反约束的数据将
会报错。在GP中使用约束是有一些限制的,最为显著的是外键(Foreign Key)、主键
(Primary Key)和唯一约束(Unique Constraint)。对其它类型约束的支持与
PostgreSQL相同。
检查约束
检查约束是最常见的约束类型。其通过指定数据必须满足一个布尔表达式来约束。
例如,要求产品的价格必须为正数,可以这样:
=# CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0)
);
非空约束
非空约束简单的理解就是不可以存在空(NULL)值。非空约束是一种Column类型
版权所有:Esena(陈淼 ) 编写:陈淼 - 97 -
Greenplum Database 管理员指南 V6.2.1
的约束。例如:
=# CREATE TABLE products (
product_no integer NOT NULL,
name text NOT NULL,
price numeric
);
唯一约束
唯一约束可以确保包含某些Column的数据在整个Table中是唯一的。在GP中使用
唯一约束存在强制限制条件,Table必须是HASH分布的或者复制分布的(而不是
DISTRIBUTED RANDOMLY),如果是HASH分布的,唯一约束的Column集合必须完整
包含所有的DK Column,也就是说,分布键字段的集合必须是唯一约束的字段集合的
子集。例如:
=# CREATE TABLE products (
product_no integer UNIQUE,
name text,
price numeric
) DISTRIBUTED BY (product_no);
复制分布的表,对唯一约束没有限制条件,因为每个Instance都包含了完整的数
据,无论如何都不会发生跨Instance检查唯一性的情况。如同之前介绍GP的分布式概
念中提到的,GP是Share-Nothing结构的,每个Instance只负责自己的数据和计算,
对于唯一约束也一样,假如唯一约束的字段不能包含全部的分布键字段,就可能需要跨
Instance检查数据的唯一性,这是无法做到的,也违反Share-Nothing的设计初衷。
主键约束
主键约束就是唯一约束与非空约束的结合体。在GP中使用主键约束存在强制条件,
Table必须是HASH分布的或者复制分布的(而不是DISTRIBUTED RANDOMLY),并且
主键约束的Column集合必须完整包含所有的DK Column。如果一个Table包含主键,
且在建表时没有指定分布键,那么主键将被用作分布键,也就是说,会把主键包含的所
有字段用作分布键。例如:
版权所有:Esena(陈淼 ) 编写:陈淼 - 98 -
Greenplum Database 管理员指南 V6.2.1
=# CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
) DISTRIBUTED BY (product_no);
创建主键和创建唯一约束+非空约束的效果是完全等价的。
外键约束
在目前版本的GP中外键约束是没有被支持的。可以定义外键约束,但参照完整性
是无效的,就是说DB不会理会定义参照完整性限制。
外键约束要求一个Table中某些Column的值必须在另外一个Table中出现。这样
可以保持两个相关表之间的数据参照完整性。在当前版本的GP中,在分布式的Table
之间的数据参照完整性检查是无效的,如同唯一约束中所述,要支持该功能,将无法避
免的需要跨Instance检查数据,性能会失控。
选择表的分布策略
GP的所有Table都是分布式存储的。在CREATE TABLE和ALTER TABLE的时候有
个DISTRIBUTED BY(HASH分布)、DISTRIBUTED RANDOMLY(随机分布)或
DISTRIBUTED REPLICATED(复制分布)子句用以决定Table的Row数据如何分布。
在选择表的分布策略时需要重点考虑以下几点(依次更重要):
平坦的数据分布 -- 为了尽可能达到最好的性能,所有的 Instance 应该尽量储
存等量的数据。若数据的分布不平衡或倾斜,那些储存了较多数据的 Instance
在处理自己那部分数据时将需要耗费更多的时间。为了达到数据的平坦分布,可以
考虑选择唯一性较高的 DK。虽然,主键往往是唯一性最好的字段,但是,不建议
为了选择一个分布键而去增加一个主键,这是一种逻辑颠倒的做法,通常,应该选
择一个常用于大表之间关联的某个唯一性较高的字段作为分布键,一般这个字段可
能在其他某个表中具有主键特征,例如,客户 ID,例如会员卡号,例如手机号码,
例如身份证号码,等等,在选择分布键时,仅需要考虑大表与大表之间的关联,任
何涉及到小表关联的场景均不应作为选择分布键的考虑因素。
版权所有:Esena(陈淼 ) 编写:陈淼 - 99 -
|
||
|
|
|