暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Citus列存介绍

原创 chirpyli 2022-09-22
2311

在介绍列存前,我们先对比一下行存与列存的区别,以便我们能更清楚的认识到他们各自适合的场景,理解什么时候应该用行存,什么情形应该用列存。

列存 OR 行存

Citus不仅支持行存,还支持列存,以适应不用的应用场景需求。行存与列存适合的应用场景不同,行存的优势在于数据写入时,一条记录命中在一个块中,IO开销相对比较小,速度快,查询多个字段时,因为记录在一个块中命中,速度快。劣势在查询少量字段时,也要访问整条记录,造成较大IO开销,同时行存压缩比相较列出小。列存按列存储,压缩比可以做到很高,查询少量字段时,所需扫描的块更少,降低了IO开销。劣势在于查询大量字段或者查询的记录数少时,要访问较多的块。简而言之就是:行存储适合非常典型的OLTP场景,而列存储适合OLAP的场景。更细化一点,什么场景最合适用列存储呢? 列存储在数据批量导入的分析场景相对行存储能够提供更好的性能,是最合适列存的场景。

Citus列存介绍

Citus Columnar基于Table Access Method Interface Definition实现,其大多数操作就与heap表基本相同。目前特性支持情况如下表:

特性 支持情况
WAL Log 支持
ROLLBACK 支持
physical replication 支持
recovery, PITR 支持
UPDATE/DELETE 不支持,仅支持Append-only
bitmap index scans 不支持
tidscans 不支持
sample scans 不支持
TOAST 不支持
ON CONFLICT语句 不支持
tuple locks(SELECT … FOR SHARE, SELECT … FOR UPDATE) 不支持
可串行化隔离级别 不支持
foreign keys、unique constraints 不支持
UNLOGGED列存表 不支持

如何创建列表表呢?可在CREATE TABLE建表时使用USING columnar

CREATE TABLE my_columnar_table ( id INT, i1 INT, i2 INT8, n NUMERIC, t TEXT ) USING columnar;

我们查看一下我们创建的列存表,可以看到其Access method不再是heap,而是columnar。

postgres@postgres=# \d+ my_columnar_table Table "public.my_columnar_table" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------+-----------+----------+---------+----------+--------------+------------- id | integer | | | | plain | | i1 | integer | | | | plain | | i2 | bigint | | | | plain | | n | numeric | | | | main | | t | text | | | | extended | | Access method: columnar -- 列存

插入数据与查询与heap表方法相同,但是不支持UPDATE/DELETE操作。不支持UPDATE/DELETE并不影响其使用,因为列存储的最佳使用场景是数据批量导入的分析场景。

-- append only postgres@postgres=# insert into my_columnar_table values (1,1,1,1,'one'); INSERT 0 1 postgres@postgres=# select * from my_columnar_table ; id | i1 | i2 | n | t ----+----+----+---+----- 1 | 1 | 1 | 1 | one (1 row) postgres@postgres=# explain select id from my_columnar_table ; QUERY PLAN ----------------------------------------------------------------------------------- Custom Scan (ColumnarScan) on my_columnar_table (cost=0.00..0.00 rows=1 width=4) Columnar Projected Columns: id (2 rows) -- not support update/delete postgres@postgres=# update my_columnar_table set n = 2; ERROR: UPDATE and CTID scans not supported for ColumnarScan postgres@postgres=# delete from my_columnar_table ; ERROR: UPDATE and CTID scans not supported for ColumnarScan

对于列存,我们还可以进行某些设置,比如指定列压缩算法,压缩级别等。支持设置可选项如下:

  • columnar.compression : 支持none|pglz|zstd|lz4|lz4hc,默认是zstd压缩算法
  • columnar.compression_level : 压缩级别,1~19
  • columnar.stripe_row_limit : 指定每个stripe中行最大记录数,默认值150000。
  • columnar.chunk_group_row_limit : 指定每个列数据块中最大行记录数,默认值10000。

可通过查columnar.options查看当前表的各项设置情况:

postgres@postgres=# select * from columnar.options ; regclass | chunk_group_row_limit | stripe_row_limit | compression_level | compression -------------------+-----------------------+------------------+-------------------+------------- events_columnar | 10000 | 150000 | 3 | zstd my_columnar_table | 10000 | 150000 | 3 | zstd (2 rows)

也可以通过SHOW进行查看,SET进行设置:

postgres@postgres=# show columnar.compression; columnar.compression ---------------------- zstd (1 row) -- 修改配置 postgres@postgres=# set columnar.stripe_row_limit = 10000; SET

列存表同样支持分区表,可根据场景,对某个分区使用行存或者列存。

CREATE TABLE parent(ts timestamptz, i int, n numeric, s text) PARTITION BY RANGE (ts); -- columnar partition CREATE TABLE p0 PARTITION OF parent FOR VALUES FROM ('2020-01-01') TO ('2020-02-01') USING COLUMNAR; -- columnar partition CREATE TABLE p1 PARTITION OF parent FOR VALUES FROM ('2020-02-01') TO ('2020-03-01') USING COLUMNAR; -- row partition CREATE TABLE p2 PARTITION OF parent FOR VALUES FROM ('2020-03-01') TO ('2020-04-01'); INSERT INTO parent VALUES ('2020-01-15', 10, 100, 'one thousand'); -- columnar INSERT INTO parent VALUES ('2020-02-15', 20, 200, 'two thousand'); -- columnar INSERT INTO parent VALUES ('2020-03-15', 30, 300, 'three thousand'); -- row

除了混合使用行存与列存的情况,我们还支持行存表与列存表之间的转换:

postgres@postgres=# select alter_table_set_access_method('my_columnar_table', 'heap'); NOTICE: creating a new table for public.my_columnar_table NOTICE: moving the data of public.my_columnar_table NOTICE: dropping the old public.my_columnar_table NOTICE: renaming the new table to public.my_columnar_table alter_table_set_access_method ------------------------------- (1 row) postgres@postgres=# \d+ my_columnar_table Table "public.my_columnar_table" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------+-----------+----------+---------+----------+--------------+------------- id | integer | | | | plain | | i1 | integer | | | | plain | | i2 | bigint | | | | plain | | n | numeric | | | | main | | t | text | | | | extended | | Access method: heap postgres@postgres=# select alter_table_set_access_method('my_columnar_table', 'columnar'); NOTICE: creating a new table for public.my_columnar_table NOTICE: moving the data of public.my_columnar_table NOTICE: dropping the old public.my_columnar_table NOTICE: renaming the new table to public.my_columnar_table alter_table_set_access_method ------------------------------- (1 row) postgres@postgres=# \d+ my_columnar_table Table "public.my_columnar_table" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description --------+---------+-----------+----------+---------+----------+--------------+------------- id | integer | | | | plain | | i1 | integer | | | | plain | | i2 | bigint | | | | plain | | n | numeric | | | | main | | t | text | | | | extended | | Access method: columnar

这样我们就可以在创建表后,根据实际数据的情况,灵活的选择列存储还是行存储,以获取更好的性能。

最后修改时间:2022-09-22 16:04:06
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论