赞
踩
本文分享自华为云社区《GaussDB(DWS)存储引擎:从CU入手优化HStore表》,作者: yd_261437590。
HStore同时拥有处理传统TP场景的事务能力和强大的数据分析能力,但是强大的数据分析能力很可能被小CU问题给破坏,另外,将多个CU排序可以增加HStore的数据聚簇性,因此作者通过解决小CU问题和提升数据聚簇性两种方式对HStore表的存取能力进行优化。
传统OLTP(OnLine Transaction Processsing 联机事务处理)场景与功能、业务强相关,数据需要进行频繁的增删改查,这时比较适合使用行存储式。行存储的优势主要有两个方面:首先是点查性能好,在点查场景下可以直接索引到某行数据的元组位置;其次就是更新效率高,行存储在实时并发入库,并发更新方面依然有着比较大的优势。
传统行存储形式的数据库主要为业务服务,但是如果涉及到分析查询场景,特别是在数据量大且复杂的查询时,就会遇到性能瓶颈了,性能瓶颈是数据存储方式决定的。因此OLTP(OnLine Transaction Processsing 联机事务处理)场景一般会交给列存储引擎去做。列存储的优势主要有两方面:首先是批量查询性能好,当分析查询只涉及某列或者某几列,不需要访问无关列,特别是在表的宽度比较大时(如一千列),优势更加明显;其次就是列存储的压缩性能更高,原因就是因为数据按列存储,单列类型相同。
列存储引擎的最小存储单位是CU(Compression Unit, 压缩单元):一个CU是由表中某一列的一部分数据组成的压缩数据块, 通过(cu_id,col_id)标识一个CU。
图1 列存储
另外,列存引擎通过delta表,避免了小CU的产生,显著提升列存表单条导入的性能,同时解决由于小CU导致的数据膨胀问题。当单条或小批量数据导入到列存表时,需先存入delta表,当delta表中数据积攒到指定行数时再存入新产生的CU中。
列存储优势明显,但是劣势也比较明显,传统列存表基本无法支持并发更新入库。随着业务复杂程度的提升,出现了对于实时入库和实时查询有较强诉求的场景,这要求数据库同时拥有处理传统TP场景的事务能力和强大的数据分析能力。这时就可以使用HStore来处理这些场景了。
图2 HStore存储
HStore利用delta表存储update/delete/insert等操作信息。之后依赖后台常驻autovacuum来做merge操作将数据写入主表。
HStore的Delta表与普通列存Delta表的对比
数仓类型 | 列存的delta表 | HStore的delta表 |
---|---|---|
表结构 | 与列存主表的表定义一致 | 与主表表定义不一样。 |
功能 | 用于暂存小批量insert的数据,满阈值后再merge到主表,避免直接insert到主表产生大量小CU。 | 用于持久化存储update/delete/insert等操作信息。 |
缺陷 | 来不及merge导致delta表膨胀,影响查询性能,同时无法解决并发update的锁冲突问题 | 依赖后台常驻autovacuum来做merge操作。 |
利用特有的delta表,HStore解决了传统列存表CU锁的问题,支持上游upsert/update等操作实时并发入库。同时还能保证和普通列存表相近的数据分析与数据压缩能力。
HStore表技术特点如下:
可以认为0 CU其实是小CU的一种特殊极端情况,0 CU相对非0的小CU对于性能影响小很多,因为0 CU只用加载deletemap。
图3 CU管理
1.小CU合并不是直接产生新的CU,而是将小CU数据重新插入到delta表后标记删除,然后依赖delta表的自动merge攒够后再产生完整的新CU;
图4 小CU合并
2.和正常的delta merge不同在于,小CU被标记删除后新插入delta表的记录会申请新的ctid,因为ctid是变化的,所以该操作和DML操作存在冲突。当DML操作时遇到小CU合并,使用等待重试的方式处理;当compact操作时遇到DML冲突时直接跳过即可,原因就是删除和更新操作还是会将数据标记删除,因此可以直接放弃合并此条数据。
图5 小CU合并时单条数据的处理
3.小CU合并的事务可见性基于现有的csn机制,compaction inprogress或者回滚对外不可见,还是看到老记录,compaction提交老记录就不再可见看到新记录。
4.具体一个CU中剩余多少条数据才算是小CU,应该是与业务强相关。因此,小CU阈值应该可以使用GUC参数调节
成功解决小CU问题,并且在小CU合并期间对实时入库性能几乎没有影响(推荐小CU行数阈值下upsert性能劣化1%),但是因为小CU问题的解决,可以很好的解决查询性能劣化,空间膨胀等问题,并且小CU合并完成后,最终实时入库性能还是会有显著提升。
在对HStore进行点查时,会首先通过CU的min/max来进行粗过滤,我们希望通过min/max过滤掉大部分数据,这就要求每个CU的数据尽可能的接近,而不能过于分散。目前GaussDB已经实现了局部聚簇 (Partial Cluster Key, 简称PCK),在数据批插过程中就会进行排序。但还是会有如下几种情况导致CU的聚簇性无法达到要求:
通过将HStore中多个CU的数据根据partial cluster key进行排序,生成新的CU再重新写入,新CU的数据会有更高的聚集性,即CU的min,max会在一个较小的区间内。异步排序时的并发处理与小CU合并类似,见3.3.1。
图6 异步排序基本原理
经过测试,排序后的CU聚簇性极大提升,粗过滤效率的提升与原本的数据特征有关。但是排序过程中会对所有参与排序的CU加CU级锁,此过程会阻塞部分DML操作,因此不建议在业务高峰期使用此功能。
本文主要讲解了如下几个方面:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。