Greenplum 性能优化之路 --(一)分区表

Greenplum分区表详解:原理、区别与优化策略
部署运行你感兴趣的模型镜像

一、什么是分区表

 

分区表就是将一个大表在物理上分割成若干小表,并且整个过程对用户是透明的,也就是用户的所有操作仍然是作用在大表上,不需要关心数据实际上落在哪张小表里面。Greenplum 中分区表的原理和 PostgreSQL 一样,都是通过表继承和约束实现的。

Greenplum 官方给出的分区表示例如下:

partitions.jpg

 

二、与分布的区别

 

分布:DISTRIBUTED

分区:PARTITION

Greenplum 中每个表都需要有一个分布键,如果你建表的时候没有显示使用语法DISTRIBUTED BY (column) 指定一个分布键,系统也会默认为你指定一个。分布目的是把数据打散到每个节点,打散的规则是 hash 或者 randomly。这样在计算时可以充分利用每个节点的资源进行并行计算。

分区特性在本文会详细介绍,两者比较如下:

  • 数据分布是在物理上拆分表数据,将数据打散到各个节点,使数据可以并行计算,这在 Greenplum 中是必须的。

  • 表分区是在逻辑上拆分大表的数据提高查询性能,也有利于数据生命周期的管理,这在 Greenplum 中是可选的。

  • 无论是分区表还是非分区表,在 Greenplum 中,数据都是分散到各个节点上的。

  • 分区不会影响数据在各个节点上的分布情况。

三、什么时候使用分区表

 

是否使用分区表,可以通过以下几个方面进行考虑:

  • 表数据量是否足够大:通常对于大的事实表,比如数据量有几千万或者过亿,我们可以考虑使用分区表,但数据量大小并没有一个绝对的标准可以使用,一般是根据经验,以及对目前性能是否满意。

  • 表是否有合适的分区字段:如果数据量足够大了,这个时候我们就需要看下是否有合适的字段能够用来分区,通常如果数据有时间维度,比如按天,按月等,是比较理想的分区字段。

  • 表内数据是否具有生命周期:通常数仓中的数据不可能一直存放,一般都会有一定的生命周期,比如最近一年等,这里就涉及到对旧数据的管理,如果有分区表,就很容易删除旧的数据,或者将旧的数据归档到对象存储等更为廉价的存储介质上。

  • 查询语句中是否含有分区字段:如果你对一个表做了分区,但是所有的查询都不带分区字段,这不仅无法提高性能反而会使性能下降,因为所有的查询都会扫描所有的分区表。

四、创建分区表

 

Greenplum 支持三种分区类型:

  1. 范围分区(Range Partition)

  2. 列表分区(List Partition)

  3. 组合分区(A combination of both types)

     

范围分区例子:

CREATE TABLE test_range_partition
(
    uid int, 
    fdate character varying(32)
)
PARTITION BY RANGE(fdate) 
(
        PARTITION p1 START ('2018-11-01') INCLUSIVE END ('2018-11-02') EXCLUSIVE, 
        PARTITION p2 START ('2018-11-02') INCLUSIVE END ('2018-11-03') EXCLUSIVE, 
        DEFAULT PARTITION pdefault
);

以上例子是按天建表,如果时间跨度比较大,会导致建表语句很长,书写起来也不方便,这时候可以使用以下语法:

CREATE TABLE test_range_partition_every_1 
(
    uid int, 
    fdate date
) 
partition by range (fdate) 
(
    PARTITION pn START ('2018-11-01'::date) END ('2018-12-01'::date) EVERY ('1 day'::interval), 
    DEFAULT PARTITION pdefault
);

 

列表分区例子:

CREATE TABLE test_list_partition
(
	uid int, 
	gender char(1)
)
PARTITION BY LIST (gender)
(
	PARTITION girls VALUES ('F'),
	PARTITION boys VALUES ('M'),
	DEFAULT PARTITION pdefault
);

多级分区例子:

CREATE TABLE test_muti_level_partition
(
	uid int, 
	gender char(1),
	fdate character varying(32)
)
PARTITION BY RANGE(fdate) 
SUBPARTITION BY LIST(gender)
SUBPARTITION template
(
	SUBPARTITION s1 VALUES ('F'),
	SUBPARTITION s2 VALUES ('M')
)
(
	PARTITION p1 START ('2018-11-01') INCLUSIVE END ('2018-11-02') EXCLUSIVE,
	PARTITION p2 START ('2018-11-02') INCLUSIVE END ('2018-11-03') EXCLUSIVE,
	DEFAULT PARTITION pdefault
)

五、管理分区表

 

分区表也是一张表,所以对于表的很多操作也可以作用于分区表上,这里列举了常用的一些操作:

清空子分区

ALTER TABLE test_range_partition TRUNCATE PARTITION p1;

删除子分区

ALTER TABLE test_range_partition DROP PARTITION p1;

注:DROP PARTITION 之后跟的是 partition name,而不是 partition table name,这两者之间是有区别的,如果是使用 EVERY 语法创建的分区表,你需要通过 pg_partitions 表查询到对应分区的 partition name。

新增子分区

ALTER TABLE test_range_partition ADD PARTITION p3 START ('2018-11-03') INCLUSIVE END ('2018-11-04') EXCLUSIVE;

注:如果分区表中含有 DEFAULT 分区,会出现如下错误,解决办法可以参见 滚动分区:

ERROR:  cannot add RANGE partition "p3" to relation "test_range_partition" with DEFAULT partition "pdefault"

滚动分区

通常按时间分区的表,都有一个特性,就是分区会不断往前滚动,比如一个按天分区,保存最近10天的分区表,每到新一天,就会要删除10天前的分表表,并且创建一个新的分区表容纳最新的数据。

如果是含有默认分区的,可以使用分区Split

ALTER TABLE test_range_partition SPLIT DEFAULT PARTITION START ('2018-11-03') INCLUSIVE END ('2018-11-04') EXCLUSIVE INTO (PARTITION p3, DEFAULT partition);

这样新分区就被添加,同时保留了默认分区,然后在删除老的分区就完成新老分区的更替。

交换分区

交换分区就是将一张普通的表和某张分区表进行交换,这个功能在数据分层存储十分有用。

比如我们会需要根据对象存储的不同目录设置分区,这个需求就可以使用交换分区完成,这样对于一张大表,他的较少查询的历史数据就可以放在对象存储上,语法如下:

ALTER TABLE {table_name} EXCHANGE PARTITION {partition_name|FOR (RANK(number))|FOR (value)} WITH TABLE {cos_table_name} WITHOUT VALIDATION;

查询分区

与分区相关的系统表或者视图如下:

pg_partition

pg_partition_columns

pg_partition_encoding

pg_partition_rule

pg_partition_templates

pg_partitions

查看分区基本信息:

t2=# select * from pg_partitions where partitiontablename = 'test_range_partition_1_prt_p1';
-[ RECORD 1 ]------------+---------------------------------------------------------------------------------------------------
schemaname               | public
tablename                | test_range_partition
partitionschemaname      | public
partitiontablename       | test_range_partition_1_prt_p1
partitionname            | p1
parentpartitiontablename | 
parentpartitionname      | 
partitiontype            | range
partitionlevel           | 0
partitionrank            | 1
partitionposition        | 2
partitionlistvalues      | 
partitionrangestart      | '2018-11-01'::character varying(32)
partitionstartinclusive  | t
partitionrangeend        | '2018-11-02'::character varying(32)
partitionendinclusive    | f
partitioneveryclause     | 
partitionisdefault       | f
partitionboundary        | PARTITION p1 START ('2018-11-01'::character varying(32)) END ('2018-11-02'::character varying(32))
parenttablespace         | pg_default
partitiontablespace      | pg_default

 

查看分区定义

t2=# select pg_get_partition_def('test_range_partition'::regclass,true);
-[ RECORD 1 ]--------+---------------------------------------------------------------------------------------------------------------
pg_get_partition_def | PARTITION BY RANGE(fdate) 
                     |           (
                     |           PARTITION p1 START ('2018-11-01'::character varying(32)) END ('2018-11-02'::character varying(32)), 
                     |           PARTITION p2 START ('2018-11-03'::character varying(32)) END ('2018-11-04'::character varying(32)), 
                     |           DEFAULT PARTITION pdefault
                     |           )

 

六、查询优化

 

分区表很大的用途在于提升分析性能,但并不是对大表进行分区就能简单的提升性能,也不是分区越多性能越好。

 

分区的粒度

通常像范围分区的表都涉及到粒度问题,比如按时间分表,究竟是按天,按周,按月等。粒度越细,每张表的数据就越少,但是分区表的数量就会越多,反之亦然。

关于分区表的数量,这里没有绝对的标准,一般来说分区表的数量在100左右已经算是比较多了。

分区表数目过多,会有多方面的影响,比如查询优化器生成执行计划较慢,同时很多维护工作也都会变慢,比如 vacuum,recovering segment,expanding the cluster, checking disk usage 等。

 

查询语句

为了充分利用分区表的优势,需要在查询语句中尽量带上分区条件。最终目的是扫描尽量少的分区表。

如下是一个静态分区消除的例子,可以看出 Partitions selected: 11 (out of 15),这里在15张分区表中选择了其中11张

t2=# explain select * from test_range_partition_every_1 where fdate >= '2018-11-05';
                                                         QUERY PLAN
                    
--------------------------------------------------------------------------------------------------------
--------------------
 Gather Motion 2:1  (slice1; segments: 2)  (cost=0.00..431.00 rows=1 width=8)
   ->  Sequence  (cost=0.00..431.00 rows=1 width=8)
         ->  Partition Selector for test_range_partition_every_1 (dynamic scan id: 1)  (cost=10.00..100.
00 rows=50 width=4)
               Filter: fdate >= '2018-11-05'::date
               Partitions selected: 11 (out of 15)
         ->  Dynamic Table Scan on test_range_partition_every_1 (dynamic scan id: 1)  (cost=0.00..431.00
 rows=1 width=8)
               Filter: fdate >= '2018-11-05'::date
 Optimizer status: PQO version 2.55.13
(8 rows)

 

注:Greenplum 最新一代的解析引擎 ORCA 是支持动态分区消除的,但是分区的选择并不会打印在执行计划中。

以下是官网的说明:

For queries that involve dynamic partition selection where the partitioning key is compared to a variable, the number of partitions that are scanned will be known only during query execution. The partitions selected are not shown in the EXPLAIN output.

七、从Redshift 迁移到数据仓库

 

使用过 Redshift 的朋友都知道,Redshift 是不支持分区表的,AWS 官方建议使用 sort key 和distribution key 来优化并行处理,官方建议如下:

CREATE TABLE Amazon Redshift does not support tablespaces, table partitioning, inheritance, and certain constraints. The Amazon Redshift implementation of CREATE TABLE enables you to define the sort and distribution algorithms for tables to optimize parallel processing. Amazon Redshift Spectrum supports table partitioning using the CREATE EXTERNAL TABLE command.

 

但是涉及到数据生命周期管理,Redshift 通常的做法是每个分区创建不同的表,而在所有表的基础上创建一个视图来管理这些表,仿造出一个分区的特性,这无疑是低效的。因此从Redshift 迁移过来的用户建议在合适的场景下使用分区特性。

 


 

 

关注“腾讯云大数据”公众号,技术交流、最新活动、服务专享一站Get~

您可能感兴趣的与本文相关的镜像

Python3.10

Python3.10

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>我们正在讨论Greenplum分区表写入性能瓶颈的监控方法。根据用户的问题,需要提供具体的监控指标、工具和方法。同时,用户引用了三篇文档,其中引用[1]提到gpfdist和gp_external_max_segs参数,引用[2]提到分区和分布策略,引用[3]提到资源组。但用户当前问题聚焦于监控,因此我们需要从监控角度出发,结合Greenplum的特性来回答。监控Greenplum分区表写入性能瓶颈,可以从以下几个层面入手:1.**系统资源监控**:观察CPU、内存、磁盘I/O和网络的使用情况,判断是否存在硬件瓶颈。2.**Greenplum内部指标**:通过系统表、视图和日志获取查询执行和资源使用的详细信息。3.**分区表特定监控**:关注分区剪枝效果、分区锁竞争、分区分布倾斜等。具体方法如下:###📊1.系统级监控指标-**CPU使用率**:通过`gpssh`和`top`命令监控所有节点(Master和Segment)的CPU使用情况。如果某个Segment的CPU持续过高,可能该分区数据倾斜。-**内存使用**:重点监控`gp_vmem_protect_limit`相关参数,防止内存溢出。通过`gp_resqueue_status`视图查看资源队列的内存使用情况(如果使用资源队列)[^3]。-**磁盘I/O**:使用`iostat`监控磁盘读写速度和等待时间。如果写入时磁盘利用率持续100%,说明磁盘成为瓶颈。-**网络流量**:使用`iftop`或`nethogs`监控节点间网络流量。Greenplum在数据写入时,Master会将数据分发到各个Segment,网络带宽不足会影响写入速度。###📈2.Greenplum内置监控工具-**gp_toolkit管理方案**:Greenplum提供了系列管理视图,位于`gp_toolkit`模式下。-`gp_toolkit.gp_disk_free`:监控磁盘剩余空间。-`gp_toolkit.gp_workfile_usage`:查看临时文件使用情况(如排序、哈希操作溢出到磁盘)[^2]。-`gp_toolkit.gp_workfile_mgr_used_diskspace`:监控所有Segment上工作文件使用的磁盘空间。-`gp_toolkit.__gp_log_segment_ext`:查看Segment的日志(需要先启用日志记录)。-**系统视图**:-`pg_stat_activity`:查看当前活动的写入会话状态,关注`waiting`字段判断是否阻塞。-`pg_locks`:监控锁等待情况,分区表写入时可能因为分区锁竞争导致延迟。-`pg_stat_all_tables`:关注具体表的`n_tup_ins`(插入行数)和`n_tup_hot_upd`(热更新行数)等统计信息。###🔍3.分区表写入专项监控-**分区剪枝效果**:通过查询计划检查是否有效剪枝。使用`EXPLAINANALYZE`查看写入语句(如`INSERT`)是否只涉及目标分区。```sqlEXPLAINANALYZEINSERTINTOsales_partitioned(...)VALUES(...);```如果计划中显示扫描了多个分区(特别是默认分区),则剪枝未生效,导致写入效率下降[^2]。-**分区锁竞争**:当多个并发写入操作同分区时,可能产生锁竞争。通过以下查询检测锁等待:```sqlSELECT*FROMpg_locksWHEREgranted=false;```结合`pg_stat_activity`找到阻塞的会话和查询。-**数据分布倾斜**:写入时若某个Segment负载过高,可能是分区键选择不当或分布键倾斜。使用以下查询检查数据倾斜:```sqlSELECTgp_segment_id,count(*)FROMsales_partitioned_1_prt_<分区名>--替换为具体分区名GROUPBYgp_segment_id;```如果某个Segment上的行数明显多于其他,则存在倾斜[^2]。###⚙️4.性能日志分析-**开启详细日志**:在`postgresql.conf`中设置日志级别:```log_statement='all'--记录所有SQLlog_min_duration_statement=1000--记录超过1秒的查询```-**使用gpperfmon**(如果安装):Greenplum的监控组件,收集系统性能数据并存储在`gpperfmon`数据库中。关键表包括:-`metrics_now`:当前性能指标快照。-`metrics_history`:历史性能数据。-重点指标:`disk_usage`(磁盘使用)、`cpu_usage`(CPU使用)、`mem_usage`(内存使用)和`net_usage`(网络使用)[^1]。###🛠️5.外部工具-**GPCC(GreenplumCommandCenter)**:商业版图形化监控工具,提供实时性能仪表盘,可直观查看写入速度、资源使用和查询状态。-**Prometheus+Grafana**:通过`node_exporter`收集系统指标,使用`postgres_exporter`收集Greenplum指标,在Grafana中展示。###📌关键性能瓶颈点总结|瓶颈类型|监控方法|优化方向||------------------|-----------------------------------|------------------------------||**CPU瓶颈**|`top`命令,Greenplum系统视图|优化查询,减少计算量||**内存瓶颈**|`gp_resqueue_status`,系统内存监控|增加内存,优化内存参数||**磁盘I/O瓶颈**|`iostat`,`gp_toolkit`视图|使用SSD,优化写入批次||**网络瓶颈**|`iftop`,网络流量监控|增加网络带宽,调整分布策略||**锁竞争**|`pg_locks`,`pg_stat_activity`|减少热点分区写入并发||**数据倾斜**|分区表Segment数据分布查询|调整分区键或分布键|通过上述监控手段,可以定位Greenplum分区表写入的性能瓶颈,并针对性地优化。---###📚相关问题1.如何优化Greenplum分区表的写入性能?2.Greenplum中如何设计分区键以避免数据倾斜?3.如何配置Greenplum的资源队列或资源组来管理写入负载?4.使用gpfdist加载数据到分区表时有哪些性能调优技巧?5.如何自动化监控Greenplum集群的写入性能?[^1]:gpfdist是Greenplum提供的种文件服务器,提供了良好的性能并且非常容易运行。gpfdist利用Greenplum系统中的所有Segment读写外部表。gp_external_max_segs服务器配置参数控制可被单gpfdist实例同时使用Segment的数量,缺省值为64。[^2]:•目标:确保数据均匀分布在所有节点,避免数据倾斜。•优化策略:•哈希分片:适合均匀分布的场景(如id字段)。sqlCREATETABLEsales(idINT,amountNUMERIC)DISTRIBUTEDBY(id);•范围分片:按时间字段分片,适合时间序列数据。sqlCREATETABLEsales_partitioned(idINT,sale_dateDATE,amountNUMERIC)PARTITIONBYRANGE(sale_date);2.表分区(Partitioning)[^3]:资源组是数据库另外种管理模式,GP4是没有这个功能,GP5之后的版本才有这个管理模式。它的内存管理模式有2种。种是基于角色,就是对数据库用户分配资源。另种是基于外部组件(例如PXF这些)在并发事务限制这块,当资源组内的并发事务达到了设置的限制时,后面的查询会等待。资源组和资源队列的区别</think>### 🛠️ Greenplum分区表写入性能瓶颈监控方法 以下为全面监控策略,涵盖系统资源、SQL执行、分区特性三个维度,结合具体工具和指标: --- #### 📊 **1. 系统资源级监控** | **监控项** | **工具/方法** | **关键指标** | **瓶颈表现** | |------------------|-------------------------------------------|---------------------------------------------|--------------------------------| | **CPU利用率** | `gpssh` + `top`/`htop` | 各Segment节点CPU > 80% | 计算密集型写入(如分区约束检查) | | **磁盘I/O** | `iostat -x 2` | `await` > 10ms, `%util` > 90% | 分区文件写入延迟 | | **网络流量** | `iftop`/`nethogs` | 主节点->Segment流量不均衡 | 数据分发倾斜(分布键失效) | | **内存压力** | `gp_toolkit.gp_workfile_mgr_*` 视图[^3] | `workfile_bytes` 持续增长 | 分区排序/哈希操作溢出到磁盘 | > **示例命令**: > ```bash > # 监控所有Segment磁盘IO > gpssh -f seg_hosts -e 'iostat -x 2' > ``` --- #### 🔍 **2. SQL执行级监控** **(1)查询计划分析** ```sql EXPLAIN (ANALYZE, VERBOSE) INSERT INTO sales_partitioned ...; ``` 关注关键点: - **分区剪枝效果**:`Partitions scanned: 1 of 365`(理想状态)[^2] - **数据倾斜**:`Slice: Unbalanced` 警告 - **锁等待**:`Lock: RowExclusiveLock` 持续时间 > 100ms **(2)实时会话监控** ```sql SELECT * FROM pg_stat_activity WHERE query LIKE '%INSERT%' AND wait_event_type = 'Lock'; ``` - **关键字段**:`wait_event`, `query_start`, `state` - **阻塞源**:锁定分区的会话ID **(3)性能计数器** ```sql SELECT * FROM gp_toolkit.gp_resqueue_status WHERE rsqname = 'pg_default'; -- 资源队列[^3] ``` - 内存溢出:`memory_used > memory_limit` - 队列堆积:`queue_cur > 0` --- #### 🎯 **3. 分区表专项监控** **(1)分区锁竞争检测** ```sql WITH locks AS ( SELECT relation::regclass AS partition_name, COUNT(*) AS lock_count FROM pg_locks WHERE locktype = 'relation' GROUP BY 1 ) SELECT * FROM locks WHERE lock_count > 5; -- 高竞争分区 ``` **(2)分区数据倾斜分析** ```sql SELECT gp_segment_id, COUNT(*) FROM sales_partitioned_1_prt_p202401 -- 指定分区 GROUP BY 1 ORDER BY 2 DESC; ``` - **危险阈值**:最大/最小Segment数据量差异 > 3倍 **(3)默认分区陷阱** ```sql SELECT count(*) FROM sales_partitioned_1_prt_default; -- 默认分区数据量[^2] ``` - **告警线**:默认分区数据量 > 总数据量的1% --- #### ⚙️ **4. 自动化监控工具链** | **工具** | **功能** | **配置要点** | |------------------------|------------------------------------------|------------------------------------------| | **GPCC** | 官方监控平台 | 设置分区表写入告警规则 | | **Prometheus+Grafana** | 自定义仪表盘 | 采集`pg_stat_partition_operations`指标 | | **pg_partman** | 分区维护扩展 | 日志记录分区自动创建/清理事件 | > **Grafana仪表盘关键面板**: > - 分区级INSERT速率 > - 各分区磁盘空间占用热力图 > - 分区锁等待时间趋势 --- #### 📌 **性能瓶颈快速定位流程** ```mermaid graph TD A[写入延迟] --> B{检查系统资源} B -->|CPU高| C[分析分区剪枝效果] B -->|I/O高| D[检查分区文件分布] B -->|网络阻塞| E[验证分布键均匀性] C --> F[存在锁竞争?] D --> G[分区数据倾斜?] E --> H[调整分布策略] F --> I[优化并发写入逻辑] G --> J[重建分布键] ``` --- ### 📚 相关问题 1. 如何优化高并发写入场景下的Greenplum分区表锁竞争? 2. 分区表数据倾斜的根本原因及纠正方法有哪些? 3. 如何配置Greenplum资源组(resource group)保障写入SLA?[^3] 4. gpfdist并行加载数据时如何避免分区热点?[^1] 5. 时间分区表的自动维护最佳实践是什么? [^1]: gpfdist是Greenplum提供的种文件服务器,提供了良好的性能并且非常容易运行。gpfdist利用Greenplum系统中的所有Segment读写外部表。gp_external_max_segs服务器配置参数控制可被单gpfdist实例同时使用Segment的数量,缺省值为64。 [^2]: 目标:确保数据均匀分布在所有节点,避免数据倾斜。优化策略:哈希分片适合均匀分布的场景(如 id 字段),范围分片按时间字段分片适合时间序列数据。 [^3]: 资源组是数据库另外种管理模式,GP4是没有这个功能,GP5之后的版本才有这个管理模式。它的内存管理模式有2种。种是基于角色,就是对数据库用户分配资源。另种是基于外部组件(例如PXF这些)在并发事务限制这块,当资源组内的并发事务达到了设置的限制时,后面的查询会等待。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值