Citus 10为Postgres带来柱状压缩

2021-03-07 09:15:57

Citus 10出了!新功能包括柱状存储& Citus在一个节点上,我们已经开放了碎片rebalancer。阅读Citus 10博客。

跳过导航Citus 10出来了!查看Citus 10博客帖子以获取所有详细信息。 CITUS是Postgres(不是叉子)的开源扩展,这也能够扩展,但也提供了其他伟大的功能。请参阅Citus Docs和Citus GitHub Repo和Readme。

这篇文章将突出显示Citus Collemar,Citus 10的一个大型新功能之一。您也可以查看柱状文档。 Citus Classar可以与Citus的扩展特征一起使用或没有缩放特征。

Postgres通常使用堆访问方法存储数据,该方法是基于行的存储。基于行的表对事务工作负载有益,但可能导致某些分析查询过多。

柱状存储是在Postgres表中存储数据的新方法。柱状组通过列而不是按行逐行进行数据;并压缩数据。按列排列数据趋于压缩良好,也意味着查询可以跳过它们不需要的列。 Columar显着减少了IO所需的IO,以便通过10x来回答典型的分析查询 -

PSQL客户端用于这些示例以使用反斜杠命令(例如\ D +,\时序)。如果使用另一个客户端,您可以省略以\开头的命令,这只是信息而非功能。

-

- 与所有Postgres扩展一样,Citus需要启用 - 用于此数据库。 - 如果不存在Citus,则创建扩展; - - 制作一个普通的表,它是基于行的存储,以及

- 柱状表。 - 创建表simple_row(i int8); 使用Columanar创建表Simple_Columnar(I Int8); - - 柱状表格像行表一样

- 插入simple_row select generate_series(1,100000); 插入simple_columnar select generate_series(1,100000); 从simple_row选择avg(i); 从simple_columnar选择avg(i); \ d + simple_row 表" public.simple_row"

列| 型号 整理| 无效| 默认 储存| 统计目标| 描述 -------- + -------- + ----------- + ---------- + --------- + --------- + ------------- + ------------- 我| bigint | | | | 平原| | 访问方法:堆 \ d + simple_columnar 表" public.simple_columnar"

列| 型号 整理| 无效| 默认 储存| 统计目标| 描述 -------- + -------- + ----------- + ---------- + --------- + --------- + ------------- + ------------- 我| bigint | | | | 平原| | 访问方法:柱状 默认访问方法是“堆”,这意味着它是一个普通的Postgres表,它是基于行的存储。 柱状表具有访问方法“ColumarAl”。 如何在行表上查询是如此缓慢,即我需要跳过前方,而柱状表上的查询快速完成。 更好的分区可视化,这使得很容易看出柱状和分区如何工作。

投影下降意味着查询可以跳过它们不需要的列,进一步减少IO

块组过滤允许查询跳过块数据组,如果元数据指示块组中的任何数据都与谓词匹配。换句话说,对于某些类型的查询和数据集,它可以快速跳过大量数据,而无需解压缩它!

这是一个微稳定的MicroBenchmark可以做些什么。这是一个“柱状友好”用例 - 一个宽的表,以及只读取一些列的查询。

创建表perf_row(

C00 INT8,C01 INT8,C02 INT8,C03 INT8,C04 INT8,C05 INT8,C06 INT8,C07 INT8,C08 INT8,C09 INT8,

C10 INT8,C11 INT8,C12 INT8,C13 INT8,C14 INT8,C15 INT8,C16 INT8,C17 INT8,C18 INT8,C19 INT8,

C20 INT8,C21 INT8,C22 INT8,C23 INT8,C24 INT8,C25 INT8,C26 INT8,C27 INT8,C28 INT8,C29 INT8,

C30 INT8,C31 INT8,C32 INT8,C33 INT8,C34 INT8,C35 INT8,C36 INT8,C37 INT8,C38 INT8,C39 INT8, C40 INT8,C41 INT8,C42 INT8,C43 INT8,C44 INT8,C45 INT8,C46 INT8,C47 INT8,C48 INT8,C49 INT8, C50 INT8,C51 INT8,C52 INT8,C53 INT8,C54 INT8,C55 INT8,C56 INT8,C57 INT8,C58 INT8,C59 INT8, C60 INT8,C61 INT8,C62 INT8,C63 INT8,C64 INT8,C65 INT8,C66 INT8,C67 INT8,C68 INT8,C69 INT8, C70 INT8,C71 INT8,C72 INT8,C73 INT8,C74 INT8,C75 INT8,C76 INT8,C77 INT8,C78 INT8,C79 INT8, C80 INT8,C81 INT8,C82 INT8,C83 INT8,C84 INT8,C85 INT8,C86 INT8,C87 INT8,C88 INT8,C89 INT8, C90 INT8,C91 INT8,C92 INT8,C93 INT8,C94 INT8,C95 INT8,C96 INT8,C97 INT8,C98 INT8,C99 INT8

); 使用columanar创建表perf_columnar(如perf_row); \时机 插入perf_row. 选择

g%00500,g%01000,g%01500,g%02000,g%02500,g%03000,g%03500,g%04000,g%04500,g%05000,

g%05500,g%06000,g%06500,g%07000,g%07500,g%08000,g%08500,g%09000,g%09500,g%10000,

g%10500,g%11000,g%11500,g%12000,g%12500,g%13000,g%13500,g%14000,g%14500,g%15000,

g%15500,g%16000,g%16500,g%17000,g%17500,g%18000,g%18500,g%19000,g%19500,g%20000,

g%20500,g%21000,g%21500,g%22000,g%22500,g%23000,g%23500,g%24000,g%24500,g%25000,

g%25500,g%26000,g%26500,g%27000,g%27500,g%28000,g%28500,g%29000,g%29500,g%30000,

g%30500,g%31000,g%31500,g%32000,g%32500,g%33000,g%33500,g%34000,g%34500,g%35000,

g%35500,g%36000,g%36500,g%37000,g%37500,g%38000,g%38500,g%39000,g%39500,g%40000, g%40500,g%41000,g%41500,g%42000,g%42500,g%43000,g%43500,g%44000,g%44500,g%45000, g%45500,g%46000,g%46500,g%47000,g%47500,g%48000,g%48500,g%49000,g%49500,g%50000 来自generate_series(1,50000000)g; 插入perf_columnar. 选择

g%00500,g%01000,g%01500,g%02000,g%02500,g%03000,g%03500,g%04000,g%04500,g%05000,

g%05500,g%06000,g%06500,g%07000,g%07500,g%08000,g%08500,g%09000,g%09500,g%10000,

g%10500,g%11000,g%11500,g%12000,g%12500,g%13000,g%13500,g%14000,g%14500,g%15000,

g%15500,g%16000,g%16500,g%17000,g%17500,g%18000,g%18500,g%19000,g%19500,g%20000,

g%20500,g%21000,g%21500,g%22000,g%22500,g%23000,g%23500,g%24000,g%24500,g%25000,

g%25500,g%26000,g%26500,g%27000,g%27500,g%28000,g%28500,g%29000,g%29500,g%30000,

g%30500,g%31000,g%31500,g%32000,g%32500,g%33000,g%33500,g%34000,g%34500,g%35000,

g%35500,g%36000,g%36500,g%37000,g%37500,g%38000,g%38500,g%39000,g%39500,g%40000, g%40500,g%41000,g%41500,g%42000,g%42500,g%43000,g%43500,g%44000,g%44500,g%45000, g%45500,g%46000,g%46500,g%47000,g%47500,g%48000,g%48500,g%49000,g%49500,g%50000 来自generate_series(1,50000000)g; 真空(冻结,分析)perf_row; 真空(冻结,分析)perf_columnar;

- 检查点如果超级用户; 否则等待系统解决 检查站; 检查站; 行表加载于2158年代,而柱状表在1271S中加载的加速为1.7倍。 柱状负载速度并不总是更好,但是当系统是绑定时,柱状确实具有优势。 对于此数据,您可以在使用柱状时看到压缩比为8倍。 真空冗长perf_columnar; 信息:" perf_columnar" :

存储ID:10000000001 总文件大小:5676548096,全数据大小:5658583219 压缩率:7。 18 x 总行计数:50000000,条纹计数:334,每条条纹平均行数:149700 CHUNK COUNT:500000,包含丢弃列的数据:0,ZSTD压缩:500000 真空

请注意,有334条纹。 条带是数据加载/写的单位。 默认情况下,每个条带最多可容纳150000元组。 默认情况下,使用ZSTD压缩压缩数据。 通过真空冗长计算的压缩率略有不同于我们在上面看到的东西,因为它仅考虑数据的平均压缩比,并且不考虑元数据(如可见性信息)。 现在让我们运行几个SQL查询。 我们将使用解释分析,以便除了整体运行时,我们还可以查看详细信息。 请注意,只需100个列中只有3个才能回答此查询。 - - 并行查询实际上在此示例中的行表上的查询减慢了,因此禁用它。 - 柱状物不支持并行查询。

- set max_parallel_workers_per_gather = 0; 解释(分析,缓冲区)通过C00从Perf_row Group中选择C00,Sum(C29),AVG(C71); 查询计划 ---------------------------------------------------------------- ---------------------------------------------------------------- ------------------------------- Hashaggregate(成本= 6430556。07 .. 6430563。57行= 500宽= 72)(实际时间= 444098。541 .. 444098。823行= 500循环= 1)

组键:C00 批次:1内存用法:169 KB 缓冲区:共享命中= 160 READ = 5555396 - > SEQ扫描perf_row(成本= 0. 00 .. 6055556。04行= 50000004宽度= 24)(实际时间= 1。159 .. 428887。294行= 50000000循环= 1) 缓冲区:共享命中= 160 READ = 5555396 规划时间:0。 146女士 JIT:

功能:7 选项:内嵌真实,优化真实,表达式真实,变形真实 时间:生成1。 702毫秒,内含5。 199毫秒,优化96。 937毫秒,发射52。 101毫秒,共155名。 938女士 执行时间:444100。 677女士 (12行) 解释(分析,缓冲区)通过C00从Perf_Columnar组中选择C00,SUM(C29),AVG(C71);

查询计划 ---------------------------------------------------------------- ---------------------------------------------------------------- -------------------------------------------- Hashaggregate(成本= 395722。35 .. 395729。85行= 500宽= 72)(实际时间= 18313。813 .. 18314。055行= 500循环= 1) 组键:C00 批次:1内存用法:169 KB 缓冲区:共享命中= 63722 Read = 27429 - > 自定义扫描(ColumeArscan)上的perf_columnar(cost = 0.00 .. 20722。35行= 50000000宽度= 24)(实际时间= 9.053 .. 9830。727行= 50000000循环= 1)

滤波器删除柱状块组:0 缓冲区:共享命中= 63722 Read = 27429 规划: 缓冲区:共享命中= 428 Read = 60 规划时间:7。 883女士 JIT: 功能:6

选项:内嵌虚假,优化false,表达式为true,变形 时间:生成0。 587毫秒,内联0。 000 ms,优化0。 319毫秒,排放4。 586毫秒,总计5。 491女士 执行时间:18336。 907女士 (15行) 我们看到读取的整体缓冲区中的剧烈差异,这导致运行时的巨大差异: 这些限制未设置为石头,我们期待将来为他们工作: 这意味着,如Citus 10,ColumNAR应用于仅用于分析查询的待附录表。 即使将来支持更新/删除,更新& 删除不会与基于行的存储器上的效率一样高效,因此柱状不适合许多事务工作负载。 但是,您可以选择并选择最佳工作的柱状,并使用它们最佳工作的行表,以获得两者的好处。

利用Citus ClounarAR的有用方法是当您将其与本机范围分区组合时。 使用ColumNAR具有分区,有助于克服更新和删除的限制,通过在同一分区表中使用行和柱状分区的混合来删除更新和删除。 通常,范围分区用于基于时间的分区。 通常,您有一个或两个最近的“活动”分区仍在更新,然后很少更新但仍然查询的许多旧分区。 在这种情况下,一个或两个活动分区可以是基于行的存储来允许更新,并且旧分区可以转换为柱状存储以受益于压缩和扫描速度。 创建表事件(TS TIMESTAMPTZ,I INT,N数字,S文本) 按范围分区(TS); 创建表events_2021_jan事件分区 从(' 2021-01-01')到(' 2021-02-01')的值;

创建表events_2021_FEB事件的分区 从(' 2021-02-01')到(' 20221-03-01&#39)的值; 插入事件选择 ' 2021-01-01' :: Timestamptz +' 0.45秒' :: interval * g, G ,

g * pi(), '数字:' || g ::文本 来自generate_series(1,10000000)g; 真空(冻结,分析)赛事_2021_FEB; 稍后,当您准备好“柱状化”旧的1月分区时,您可以使用此Citus提供的功能从行转换为柱状存储: 选择alter_table_set_access_method(' events_2021_jan','柱状');

真空(冻结,分析)活动_2021_jan; - 检查点如果超级用户; 否则等待系统解决 检查站; 检查站; 现在,您可以看到1月分区是柱状,2月分区是行存储(“堆”)。 \ D + EVENT_2021_JAN 表" public.events_2021_jan"

列| 型号 整理| 无效| 默认 储存| 统计目标| 描述 -------- + -------------------------------- + - -------- + --------- + ---------- + ------------- + ----- -------- TS | 时区的时间戳| | | | 平原| | 我| 整数| | | | 平原| | n | 数字| | | | 主要| | s | 文字| | | | 延期| | 分区:来自(' 2021-01-01 00:00:00 + 00')的值的事件(' 2021-02-01 00:00:00 + 00')

分区约束:((ts不是null)和(ts> =' 2021-01-01 00:00:00 + 00' ::时间戳与时区)和(ts< 39 ; 2021-02-01 00:00:00 + 00' ::时间戳与时区))) 访问方法:柱状 \ d + events_2021_FEB 表" public.events_2021_FEB" 列| 型号 整理| 无效| 默认 储存| 统计目标| 描述 -------- + -------------------------------- + - -------- + --------- + ---------- + ------------- + ----- --------

TS | 时区的时间戳| | | | 平原| | 我| 整数| | | | 平原| | n | 数字| | | | 主要| | s | 文字| | | | 延期| | 分区:来自(' 2021-02-01 00:00:00 + 00')的值的事件(' 20221-03-01 00:00:00 + 00') 分区约束:((ts不是null)和(ts> =' 2021-02-01 00:00:00 + 00' ::时间戳与时区)和(ts<&#39 ; 2021-03-01 00:00:00 + 00' ::时间戳与时区))) 访问方法:堆

他们每个人都有大约一半的行。 但即使1月的分区有更多的行,它导致柱状压缩很小: 从事件中选择count(*); - 父表扫描两个分区 数数 ---------- 10000000 (1行)

从events_2021_jan中选择count(*); 数数 --------- 5951999. (1行) 从events_2021_FEB中选择Count(*);

数数 --------- 4048001 (1行) 选择pg_size_pretty(pg_relation_size(' events_2021_jan')); pg_size_pretty.

----------------- 69 MB. (1行) 选择pg_size_pretty(pg_rezation_size(' sements_2021_feb')); pg_size_pretty. -----------------

264 MB. (1行) 让我们在事件表的1月分区分区中为特定小时进行查询。 解释(分析,缓冲) 选择sum(n) 来自Events_2021_Jan. 其中Ts> =' 2021-01-11 01:00' :: Timestamptz和

TS< ' 2021-01-11 02:00' :: Timestamptz; 查询计划 ---------------------------------------------------------------- ---------------------------------------------------------------- ------------------------------------ 汇总(成本= 4438。09 .. 4438。10行= 1宽= 32)(实际时间= 8. 356 .. 8。357行= 1循环= 1) 缓冲区:共享命中= 2922 Read = 2 - > Sements_2021_jan上的自定义扫描(ColumanArscan)(成本= 0. 00。4418。55行= 7815宽度= 11)(实际时间= 2。998 .. 7。703行= 8000循环= 1) 过滤器:((TS> =' 2021-01-11 01:00:00 + 00' ::时间戳与时区)和(Ts<< 39; 2021-01-11 02: 00:00 + 00' ::时间戳与时区)))

过滤器删除的行:12000 滤波器删除柱状块组:594 缓冲区:共享命中= 2922 Read = 2 规划: 缓冲区:共享命中= 27渐渐= 2 规划时间:0。 233女士 执行时间:8。 380毫安

(11行)

条纹:柱状表中的所有加载都分为150000行的条纹(默认情况下)。读取给定列时,条纹越大,越序列。

块组:条纹进一步分解为10000行的块组(默认情况下)。

块:每个块组由每列的一个块组成。块是压缩的单位,为每个块跟踪MIN / MAX以使能块组过滤。

块组过滤:当查询的WHERE子句不能匹配块中的任何元组时,我们知道,通过块的最小值/最大值,然后块组过滤将简单地跳过整个块组而不解决块组中的任何块。

您可以在上面筛选出来的594个块组,这意味着筛选了5931999行,而无需提取或解压缩数据。只需要2个块组(20000行)实际获取和解压缩,这就是查询仅占毫秒的原因。

Citus Colulsar是Citus开源扩展中包含的新功能,它们共享相同的代码存储库。要使用Postgres的新柱状功能,您只需创建Citus扩展,使用ColleNAR语法创建表格,即您已准备就绪(当然,阅读Citus Docs!)。

CITUS以其扩展Postgres的能力而闻名。 重要的是,您可以使用或不使用Citus横向扩展功能使用Citus Clounarar。 柱状是一个伟大的 ......