Greenplum行存与列存的选择以及转换方法

本文涉及的产品
云数据库 PolarDB MySQL 版,列存表分析加速 8核16GB
RDS Agent(兼容OpenClaw),2核4GB
PolarDB Agent Express,2核4GB
简介:

背景

数据在数据库中的存储形式多种多样,比较常见的如

1. PostgreSQL的堆表,以行的形式存储,(当变成字段压缩后的长度超过数据块的四分之一时,会以TOAST的形式存储到TOAST表)。

2. MySQL innodb则是以b+tree形式存储的。

  1. 在数据仓库产品中,如Greenplum,支持行存,也支持列存。

    还有很多存储格式,本文将讨论行存和列存应该如何选择呢?

行存储优劣分析

Greenplum行存储(堆表)的优势在哪里?

数据顺序写入BLOCK中,持续写入的情况下,一条记录命中在一个块中,IO开销相对比较小,速度较快。

查询多个字段时,因为记录在一个块中命中,速度较快。

Greenplum行存储(堆表)的劣势在哪里?

查询少量字段时,也要访问整条记录,造成一定的IO浪费。

行存储的压缩比有限。

行存储适合什么应用场景

行存储适合非常典型的OLTP应用场景。

列存储优劣分析

Greenplum列存储的优势在哪里?

数据按列存储,压缩比可以做到很高。

当查询少量字段时,扫描的块更少,可以节约IO还能提升效率。

Greenplum列存储的劣势在哪里?

因为是按列存储的,当需要查询大量字段时,或者查询的记录数偏少时,会造成离散IO较多。

例如查询1条记录的20个列,行存储可能只需要扫描1个块,而列存储至少需要扫描20个块。

由于IO的放大,列存储不适合OLTP的场景,如有大量的更新,查询操作。

列存储适合什么应用场景

列存储适合非常典型的OLAP应用场景,按列做较大范围的聚合分析,或者JOIN分析。

如何设置表的存储格式

建表时,在with(storage parameter)中指定
screenshot

screenshot

或者在分区的with(storage parameter)中指定
screenshot

或者在子分区的with(storage parameter)中指定
screenshot

screenshot

因此Greenplum的存储格式支持到了子分区这个级别,一张表(指父表)可以混合使用行存储与列存储。

如何转换表的存储格式

screenshot

screenshot

行列混合存储应用场景

例如用户如果有一张按时间分区的表,最近1个月的查询类似OLTP的请求,需要查询较多字段,而一个月以前的表则OLAP的需求更旺盛。

这种情况下,我们的需求是将老的分区转换为列存储,怎么做呢?

例子

创建分区表,选择行存储

create table t_digoal (id int, info text, crt_time timestamp) distributed by (id) partition by range(crt_time) (start (date '2016-08-01') inclusive end (date '2016-12-01') exclusive every (interval '1 day'));

查看分区定义

postgres=> select * from pg_partitions;
-[ RECORD 1 ]------------+----------------------------------------------------------------------------------------------------------------------------------------------
schemaname               | public
tablename                | t_digoal
partitionschemaname      | public
partitiontablename       | t_digoal_1_prt_1
partitionname            | 
parentpartitiontablename | 
parentpartitionname      | 
partitiontype            | range
partitionlevel           | 0
partitionrank            | 1
partitionposition        | 1
partitionlistvalues      | 
partitionrangestart      | '2016-08-01 00:00:00'::timestamp without time zone
partitionstartinclusive  | t
partitionrangeend        | '2016-08-02 00:00:00'::timestamp without time zone
partitionendinclusive    | f
partitioneveryclause     | '1 day'::interval
partitionisdefault       | f
partitionboundary        | START ('2016-08-01 00:00:00'::timestamp without time zone) END ('2016-08-02 00:00:00'::timestamp without time zone) EVERY ('1 day'::interval)
parenttablespace         | pg_default
partitiontablespace      | pg_default
-[ RECORD 2 ]------------+----------------------------------------------------------------------------------------------------------------------------------------------
schemaname               | public
tablename                | t_digoal
partitionschemaname      | public
partitiontablename       | t_digoal_1_prt_2
partitionname            | 
parentpartitiontablename | 
parentpartitionname      | 
partitiontype            | range
partitionlevel           | 0
partitionrank            | 2
partitionposition        | 2
partitionlistvalues      | 
partitionrangestart      | '2016-08-02 00:00:00'::timestamp without time zone
partitionstartinclusive  | t
partitionrangeend        | '2016-08-03 00:00:00'::timestamp without time zone
partitionendinclusive    | f
partitioneveryclause     | '1 day'::interval
partitionisdefault       | f
partitionboundary        | START ('2016-08-02 00:00:00'::timestamp without time zone) END ('2016-08-03 00:00:00'::timestamp without time zone) EVERY ('1 day'::interval)
parenttablespace         | pg_default
partitiontablespace      | pg_default

创建列存单表,用于交换分区

postgres=> create table t_digoal_col(id int, info text, crt_time timestamp) with (appendonly=true, ORIENTATION=column) distributed by (id);
CREATE TABLE

将历史分区数据插入列存储的交换分区

insert into t_digoal_col select * from t_digoal_1_prt_1;

指定对应的rank,交换分区

alter table t_digoal exchange partition for (rank(1)) with table t_digoal_col with validation;

可以使用 without validation 加快速度。

祝大家玩得开心,欢迎随时来 阿里云促膝长谈业务需求 ,恭候光临

阿里云的小伙伴们加油,努力 做好内核与服务,打造最贴地气的云数据库

目录
相关文章
|
Ubuntu Unix Linux
Linux系统之rename命令的基本使用
Linux系统之rename命令的基本使用
875 41
|
NoSQL fastjson Redis
自定义限流注解@RateLimiter
自定义限流注解@RateLimiter
553 2
|
SQL 监控 关系型数据库
PostgreSQL普通表转换成分区表
如何使用pg_rewrite扩展将普遍表转换成分区表
|
人工智能
技术心得记录:关于自补图的认识和构造(无证明)
技术心得记录:关于自补图的认识和构造(无证明)
964 0
|
敏捷开发 存储 数据管理
自动化测试框架设计:从理论到实践
【7月更文挑战第13天】本文将深入探讨自动化测试框架的设计原理与实现方法。通过分析自动化测试的必要性和框架设计的基本原则,结合具体案例,展示如何从零开始构建一个高效、可维护的自动化测试系统。文章不仅涵盖框架的结构设计,还包括最佳实践和常见问题的解决策略,为读者提供一套完整的解决方案和实操指南。
|
Android开发
【通讯录教程】苹果安卓鸿蒙系统通用,如何大批量导入手机号码到手机的通讯录,下面教你方法,只需1分钟搞定几万个号码的导入手机电话本
该文介绍了一种快速批量导入手机通讯录的方法,适用于处理大量手机号的需求,如微商管理、客户资料整理等。在QQ同步助手开始收费后,提供了免费的替代方案。步骤包括:下载批量导入软件(链接提供腾讯云盘和百度网盘地址),清空通讯录(非必需),制作符合格式的通讯录文件,并按操作系统(苹果、安卓或鸿蒙)进行导入。整个过程只需1分钟,简便快捷。
3512 2
|
关系型数据库
PostgreSQL 百亿级数据范围查询, 分组排序窗口取值 极致优化 case
本文将对一个任意范围按ID分组查出每个ID对应的最新记录的CASE做一个极致的优化体验。优化后性能维持在可控范围内,任意数据量,毫秒级返回,性能平稳可控。比优化前性能提升1万倍。 CASE如下: 有一张数据表,结构: CREATE TABLE target_position
17508 0
|
存储 程序员 Shell
【C/C++ 基本语法 结构体】C++ 结构体声明(定义)以及不同写法的差异
【C/C++ 基本语法 结构体】C++ 结构体声明(定义)以及不同写法的差异
669 1
|
SQL Kubernetes 安全
国产数据库-技术特性-CloudberryDB
Cloudberrydb基于gpdb,支持PG14内核,有很多GP目前不支持的优秀特性
952 0
|
存储 SQL JSON
5、DataX(DataX简介、DataX架构原理、DataX部署、使用、同步MySQL数据到HDFS、同步HDFS数据到MySQL)(一)
5、DataX(DataX简介、DataX架构原理、DataX部署、使用、同步MySQL数据到HDFS、同步HDFS数据到MySQL)(一)