Greenplum 在表的存储结构上分为 HEAP 表、AO 表。
其中 HEAP 表是 PG 数据库原生存储格式,也是 Greenplum 的默认存储格式,但是只支持行存储,并且不能压缩。AO 表为 append optimized 表,支持行存储、列存储,支持多种压缩算法与压缩级别。
AO 表原理
Greenplum 4.3 之前 AO 表为 appendonly 表,只能追加,即只能进行插入,不能更新和删除。Greenplum 4.3 之后,AO 表优化为 append optimized 表,支持插入、更新、删除。插入即在最后追加记录;删除通过维护一张 bitmap 表,标记被删除的行;更新则为删除和插入 2 个操作的组合。所以 append optimized 表在大量更新或删除之后,标记为无效的数据不会自动清除,需要使用 vaccum 命令回收这部分空间。
bitmap 表如下,通过 bit 位以及偏移量来判定 AO 表上的某一行是否被删除(其中 82342 为 AO 表的 relid,bitmap 表就为 pg_aoseg.pg_aovisimap_{relid}):
lzk=# select * from pg_aoseg.pg_aovisimap_82342;
segno | first_row_no | visimap
-------+--------------+----------------------------------------
2 | 1081344 | \x0100000081002cbc002000008c00
2 | 2064384 | \x0100000084002ff2ff00c80000000bfcbd80
2 | 1114112 | \x0100000084002ff2ff266c00020000bfca48
2 | 3440640 | \x0100000081002f5c000020008180
2 | 4259840 | \x0100000084002ff2ff28bc00000100bfc9b4
2 | 5079040 | \x01000000804022dc000800008380
2 | 3211264 | \x0100000082002ff26dc00400000a34
2 | 1638400 | \x0100000082002ff25dc00080000a74
2 | 458752 | \x0100000084002ff2ff2ff223c00000020b54
(9 rows)
对于 heap 表,由 tupleid 决定每条记录的位置(tupleid 包含记录在文件中偏移位置),而对于 AO 表,数据是压缩的,没法确定 value 在文件中偏移位置,因此使用了 rownum,每条记录都有自己的 rownum,rownum 一直增长,每个 block 中记录了起始 rownum 以及 block 在文件中偏移位置,所以只要给定一个 rownum,就能定位到所在的 block,然后从 block 中就可以遍历到这个 rownum 对应的记录。
列存原理
列存只能是 AO 表,所以上一节中所有的 AO 表原理都适用。列存表,按列,每列对应一个或一批文件,每个列占用一个至多个文件,最多 128 个(预留 128 个 id),不同列的值不会同时出现一个文件。
列存表的文件存储,即(25854.1,25854.2 为第一列,25854.129、25854.130 为第二列,以此类推):
[gpadmin@host10372181 /data1/primary/gpseg0/base/82341]$ll|grep 25854
-rw------- 1 gpadmin gpadmin 0 Jul 14 16:48 25854
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.1
-rw------- 1 gpadmin gpadmin 6168 Jul 16 14:14 25854.1025
-rw------- 1 gpadmin gpadmin 3108976 Jul 15 15:47 25854.1026
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.1153
-rw------- 1 gpadmin gpadmin 1476776 Jul 15 15:47 25854.1154
-rw------- 1 gpadmin gpadmin 5976 Jul 16 14:14 25854.1281
-rw------- 1 gpadmin gpadmin 2746744 Jul 15 15:47 25854.1282
-rw------- 1 gpadmin gpadmin 6160 Jul 16 14:14 25854.129
-rw------- 1 gpadmin gpadmin 2626616 Jul 15 15:47 25854.130
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.1409
-rw------- 1 gpadmin gpadmin 1360584 Jul 15 15:47 25854.1410
-rw------- 1 gpadmin gpadmin 5848 Jul 16 14:14 25854.1537
-rw------- 1 gpadmin gpadmin 2559240 Jul 15 15:47 25854.1538
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.1665
-rw------- 1 gpadmin gpadmin 1257912 Jul 15 15:47 25854.1666
-rw------- 1 gpadmin gpadmin 6368 Jul 16 14:14 25854.1793
-rw------- 1 gpadmin gpadmin 2106232 Jul 15 15:47 25854.1794
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.1921
-rw------- 1 gpadmin gpadmin 17856504 Jul 15 15:47 25854.1922
-rw------- 1 gpadmin gpadmin 279528 Jul 15 15:47 25854.2
-rw------- 1 gpadmin gpadmin 7016 Jul 16 14:14 25854.2049
-rw------- 1 gpadmin gpadmin 66013896 Jul 15 15:47 25854.2050
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.2177
-rw------- 1 gpadmin gpadmin 16055520 Jul 15 15:47 25854.2178
-rw------- 1 gpadmin gpadmin 6208 Jul 16 14:14 25854.2305
-rw------- 1 gpadmin gpadmin 22774616 Jul 15 15:47 25854.2306
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.2433
-rw------- 1 gpadmin gpadmin 7181688 Jul 15 15:47 25854.2434
-rw------- 1 gpadmin gpadmin 7032 Jul 16 14:14 25854.2561
-rw------- 1 gpadmin gpadmin 14922064 Jul 15 15:47 25854.2562
-rw------- 1 gpadmin gpadmin 11176 Jul 16 14:14 25854.257
-rw------- 1 gpadmin gpadmin 11304392 Jul 15 15:47 25854.258
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.2689
-rw------- 1 gpadmin gpadmin 5351744 Jul 15 15:47 25854.2690
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.2817
-rw------- 1 gpadmin gpadmin 201488 Jul 15 15:47 25854.2818
-rw------- 1 gpadmin gpadmin 6160 Jul 16 14:14 25854.2945
-rw------- 1 gpadmin gpadmin 3593248 Jul 15 15:47 25854.2946
-rw------- 1 gpadmin gpadmin 9824 Jul 16 14:14 25854.3073
-rw------- 1 gpadmin gpadmin 12571176 Jul 15 15:47 25854.3074
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3201
-rw------- 1 gpadmin gpadmin 3308464 Jul 15 15:47 25854.3202
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3329
-rw------- 1 gpadmin gpadmin 3258376 Jul 15 15:47 25854.3330
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3457
-rw------- 1 gpadmin gpadmin 1604200 Jul 15 15:47 25854.3458
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3585
-rw------- 1 gpadmin gpadmin 3483096 Jul 15 15:47 25854.3586
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3713
-rw------- 1 gpadmin gpadmin 354840 Jul 15 15:47 25854.3714
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3841
-rw------- 1 gpadmin gpadmin 329024 Jul 15 15:47 25854.3842
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.385
-rw------- 1 gpadmin gpadmin 1204480 Jul 15 15:47 25854.386
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.3969
-rw------- 1 gpadmin gpadmin 363400 Jul 15 15:47 25854.3970
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4097
-rw------- 1 gpadmin gpadmin 368080 Jul 15 15:47 25854.4098
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4225
-rw------- 1 gpadmin gpadmin 213120 Jul 15 15:47 25854.4226
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4353
-rw------- 1 gpadmin gpadmin 187264 Jul 15 15:47 25854.4354
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4481
-rw------- 1 gpadmin gpadmin 218800 Jul 15 15:47 25854.4482
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4609
-rw------- 1 gpadmin gpadmin 1687376 Jul 15 15:47 25854.4610
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4737
-rw------- 1 gpadmin gpadmin 761744 Jul 15 15:47 25854.4738
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.4865
-rw------- 1 gpadmin gpadmin 10054680 Jul 15 15:47 25854.4866
-rw------- 1 gpadmin gpadmin 6624 Jul 16 14:14 25854.513
-rw------- 1 gpadmin gpadmin 2743616 Jul 15 15:47 25854.514
-rw------- 1 gpadmin gpadmin 5280 Jul 16 14:14 25854.641
-rw------- 1 gpadmin gpadmin 1149328 Jul 15 15:47 25854.642
-rw------- 1 gpadmin gpadmin 5632 Jul 16 14:14 25854.769
-rw------- 1 gpadmin gpadmin 1861056 Jul 15 15:47 25854.770
-rw------- 1 gpadmin gpadmin 6160 Jul 16 14:14 25854.897
-rw------- 1 gpadmin gpadmin 2020608 Jul 15 15:47 25854.898
若只更新某1列或某几列,对于列存 AO 表,每个列文件之间并没有指针或其他关联,依靠相同的 rownum 来定位一行数据,所有列文件中该 rownum 数据全部作废,然后使用更新后的数据插入到新的一行中,此行中的所有 rownum 保留。因此,此时的数据更新,并不是只更新指定的列。所以单条 update 带来的 IO 开销很大,需要对每一个列文件都写入。
小结
对于 Greenplum 中的 AO 表,其实无论是行存或列存,更新所带来的性能降低是可以预估的。一条 SQL 语句的执行时间基本上可以简单的分为 IO 消耗的时间和计算时间。一张表在大量更新之后只会线性的增加 IO 时间,计算时间并不会受到影响。即假设表 A 通过 update 更新了 30% 的数据,同样的一条 SQL 执行时间的延长理论上不高于 30%。并且可以通过 vacuum 回收被删除数据的空间来恢复原有的查询性能。