OceanBase PoC 经验总结(二)—— AP 业务
<blockquote><p>首先为大家推荐这个 OceanBase 开源负责人老纪的公众号 “老纪的技术唠嗑局”,会持续更新和 #<strong>数据库</strong>、#<strong>AI</strong>、<strong>#技术架构</strong> 相关的各种技术内容。欢迎感兴趣的朋友们关注!</p>
</blockquote>
<h1 id="背景"><strong>背景</strong></h1>
<p>前段时间,OceanBase 社区公众号转载了庆涛大佬的一篇《OceanBase PoC 经验总结(一)》,为大家介绍了他积累的大量 OceanBase PoC 经验。不过庆涛日理万机,之前预告的一篇和 SQL 有关的 PoC 文章还在持续打磨中。</p>
<p>虽说好饭不怕晚,但我还是先替庆涛给大家提前加个餐,拿自己的狗尾续个貂。</p>
<p>这篇 OceanBase AP 业务的 PoC 经验总结,是我在白华大佬做相关技术分享时记录的一个笔记,主要是业务平迁和数据库对象设计,不会涉及太多运维。</p>
<p><img alt="" loading="lazy" src="https://intranetproxy.alipay.com/skylark/lark/0/2025/png/32756313/1751874215668-b35301d3-b15d-471e-a504-8fb8c6fddf81.png" class="lazyload"></p>
<p>PoC (Proof of Concept ) 的含义是:</p>
<p>概念验证,是一种验证某个理论或解决方案是否可行的过程或实践。</p>
<p>它的主要目的是:通过一个简单、快速且低成本的实现方式来展示某个框架、技术、方案或项目是否能够达到预期目标,确认可行性或者探讨潜在的应用场景。</p>
<p>今天把学习笔记在社区公众号中共享出来,希望能够帮助 OceanBase 社区版的用户们在 PoC 的过程中少踩一些坑。话不多说,正文开始。</p>
<h1 id="平迁策略"><strong>平迁策略</strong></h1>
<p>我们这次讨论的 OceanBase AP 场景 PoC,是替换原有 AP 系统。也就是说,前提是:默认原有业务数据库的 schema 模型等都已经是被验证过的,而不是重新为新业务设计。</p>
<p><strong>整体来看,可以采用平迁策略。即原系统是行存,用 OB 替换之后也是行存;原系统是列存,替换之后也是列存。聚集键、分区键等也保持和原系统保持一致即可。识别出特殊场景后,再做不一致设计。</strong></p>
<p>这里只有索引比较特殊,不是完全平替。一些 AP 数据库,索引创建的可能会比较随意,数量极大。在 OceanBase 中,索引尽量按业务需求来创建,在替换时应该只保留需要的索引。</p>
<h1 id="表结构设计"><strong>表结构设计</strong></h1>
<p>这里有一个在表格,列举了主流 AP 数据库中,表结构设计时需要关注的一些要点。</p>
<p>表格中的内容不全,可能会在后面的学习笔记中继续完善和修改。表格中只罗列一些信息,主要是为了在不同数据库间进行术语转换。</p>
<table>
<thead>
<tr>
<th style="text-align: left">** **</th>
<th style="text-align: left"><strong>OceanBase</strong></th>
<th style="text-align: left"><strong>Other AP DataBases</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">数据聚集 (Data Clustering)</td>
<td style="text-align: left">+ 堆表<sup></sup>: 插入序 <br>+ 索引组织表: 主键序</td>
<td style="text-align: left">+ CLUSTERED KEY <br>+ ORDER BY <br>+ CLUSTER ON</td>
</tr>
<tr>
<td style="text-align: left">数据分布 (Data Distribution)</td>
<td style="text-align: left">+ 分区 <br> - 通常一级时间维度 range 分区</td>
<td style="text-align: left">+ DISTRIBUTED BY <br> - HASH / RANDOM / ROUNDROBIN / REPLICATED</td>
</tr>
<tr>
<td style="text-align: left">合并策略</td>
<td style="text-align: left">+ 手动合并 <br>+ table_mode: <br> - normal <br> - queuing <br> - moderate <br> - super <br> - extreme</td>
<td style="text-align: left">+ None <br>+ 手动合并</td>
</tr>
<tr>
<td style="text-align: left">分区管理</td>
<td style="text-align: left">+ 手动分区 <br>+ ODC 设置分区计划<sup></sup> <br>+ 435 BP2 自动分区分裂<sup></sup> <br>+ 435 BP2 动态分区管理<sup></sup></td>
<td style="text-align: left">+ LIFECYCLE <br>+ TTL(partition_retention_condition)<br>+ 动态分区管理</td>
</tr>
<tr>
<td style="text-align: left">colocate</td>
<td style="text-align: left">tablegroup</td>
<td style="text-align: left">colocate_with</td>
</tr>
<tr>
<td style="text-align: left">聚合表</td>
<td style="text-align: left">Alternative MV</td>
<td style="text-align: left">+ Aggregation Table <br>+ Alternative MV</td>
</tr>
<tr>
<td style="text-align: left">最小迁移单位</td>
<td style="text-align: left">partition / tablet</td>
<td style="text-align: left">+ shard <br>+ tablet <br>+ share storage <br>+ segment</td>
</tr>
</tbody>
</table>
<pre><code>- 二级 hash 分区
</code></pre>
<ul>
<li>
<p>tablegroup sharding</p>
</li>
<li>
<p>primary zone</p>
</li>
<li>
<p>复制表</p>
</li>
<li>
<p>BROADCAST</p>
</li>
</ul>
<p>上面这个表格太大,不适合在手机上阅读,接下来就通过文字来简单记录下这张表格中的要点。</p>
<h2 id="数据聚集"><strong>数据聚集</strong></h2>
<p><strong>大多 AP 数据库都是按时间维度(由老到新)做聚集的堆表,对应 OceanBase 中的堆表。如果其他 AP 数据库用到了 CLUSTERED KEY,对应的则是 OceanBase 的索引组织表(默认)。</strong> 在 OceanBase 中,可以通过 default_table_organization 配置项来控制创建的表类型默认是堆表还是索引组织表。</p>
<p>附上一个堆表和索引组织表的示意图(图中蓝色表示同属于具体一个用户的数据,红色表示同属于一天的数据)。</p>
<ul>
<li>按时间聚集(堆表默认):</li>
</ul>
<p><img alt="" loading="lazy" src="https://intranetproxy.alipay.com/skylark/lark/0/2025/png/32756313/1751874215670-4411cba4-c6e6-401a-8787-d1ae17a797eb.png" class="lazyload"></p>
<ul>
<li>按用户聚集(索引组织表,主键为 user):</li>
</ul>
<p><img alt="" loading="lazy" src="https://intranetproxy.alipay.com/skylark/lark/0/2025/png/32756313/1751874215661-c5b716c5-ea43-4ecc-a790-0d288128bfa5.png" class="lazyload"></p>
<ul>
<li>按时间聚集 + 分区:</li>
</ul>
<p><img alt="" loading="lazy" src="https://intranetproxy.alipay.com/skylark/lark/0/2025/png/32756313/1751874215703-fdaea28e-7f38-4fd9-b5ba-63c4933bed84.png" class="lazyload"></p>
<p>在常见的 AP 数据库中,有一些是通过 clustered key 进行数据聚集,还有个别的数据库数据聚集方式相对复杂,会分成很多层次。因为不同数据库的数据聚集方式可能都有一些出入,所以把某些 AP 数据库里的索引直接平迁到 OceanBase 里作为主键,可能并不合适。需要先理解原数据库的数据聚集方式,以及分片是怎么拆到多个机器上的,否则可能会出问题。</p>
<h2 id="数据分布"><strong>数据分布</strong></h2>
<p>数据分布这里,可以简单理解成怎么把数据分布到多台机器上去。除了 share storage 的数据库,其他都是要考虑数据分布的。</p>
<p>很多 AP 数据库都有分区(partition)+ 数据分布(distributed key)。其中分区(partition)是用于做数据管理的,例如可以把用于存放三年之前旧数据的分区给 drop 掉。而数据分布式单独设计的。<strong>当原数据库的表有 partition + distributed key 的时候,就需要在 OceanBase 中的对应表中设计分区键了。数据分区方式参考原数据库即可,例如 partition by 对应一级分区,distributed by 对应二级分区。</strong></p>
<p>这里再介绍一个 AP 场景非常典型的表结构设计:堆表 (4.3.5.1 OLAP 模式默认为堆表) + 时间纬度一级 range 分区 + 业务纬度二级 hash 分区。</p>
<p>在 OceanBase 中,除了分区,还有 tablegroup、复制表、primary zone 等概念,这里不再一一解析。</p>
<h2 id="合并策略"><strong>合并策略</strong></h2>
<p>这里需要了解的就是 OceanBase 中 buffer 表的自适应合并优化配置,详见:《在 OceanBase 中,如何应对存储引擎的读放大问题?》](https://mp.weixin.qq.com/s?__biz=Mzk3NTE2NzU5NQ==&mid=2247485458&idx=1&sn=cd2fc617a2406d01891d827348f50fca&scene=21#wechat_redirect)</p>
<p>我上面这篇公众号文章的标题起的不好,有点儿文不对题,但想改的时候已经晚了,实际就是在介绍表级配置项 table mode 五种不同档位的合并策略。</p>
<h2 id="分区管理"><strong>分区管理</strong></h2>
<p>OceanBase 的分区管理这里,最常见的一般都是手动设置分区。在 AP 场景中最最常见的一般是上面提到过的一级 range 分区(时间维度),二级 hash 分区。</p>
<p>除此以外,OceanBase 还有一些自动分区的能力:</p>
<ul>
<li>ODC 设置分区计划<sup></sup></li>
<li>435 BP2 自动分区分裂<sup></sup></li>
<li>435 BP2 动态分区管理<sup></sup></li>
</ul>
<p>之前比较常见的是通过 ODC 设置自动创建和清理分区。</p>
<p>现在 435 BP2 及以上版本,内核就会直接支持自动分区分裂和动态分区管理(后续内核研发同学会继续在这个公众号上发布自动分区分裂等相关的技术内容,也会通过在线体验和线上直播等社区活动为大家详细介绍这些功能)。</p>
<h2 id="排序规则"><strong>排序规则</strong></h2>
<p><strong>AP 场景中,建议是尽量把业务中字符串类型的排序规则设置成 binary,例如 <strong><strong>COLLATE</strong></strong> = utf8mb4_bin。</strong> 因为直接比较二进制的,不用在比较时还去考虑大小写是否敏感等问题,效率会比其他 collation 中的比较方式高很多,这很好理解。</p>
<p>我之前也写过 OceanBase 中一些字符串表达式的优化代码,所以知道内核中很多和字符串相关的操作,都会有仅对 binary 生效的各种短路优化,还可以进一步提升性能。</p>
<p>在上面的表格中也可以看到,很多主流的纯 AP 数据库,都只支持 utf8 binary,因为逻辑简单,效率高,还容易通过各种奇技淫巧进行优化。如果支持了其他的 collation,默认一般也都是忽略大小写的。</p>
<p>这个点虽然又小又老生常谈,但是很重要。OceanBase 有一些 AP 用户,collation 本来可以用 binary,但还是设置成了其他的,例如 xxx_general_ci 等。上线之后改起来就会很麻烦,重排数据一般都是 Offline DDL,而且重排要花费的时间也和数据量相关,耗时不可控,只能避开业务窗口来调整。所以要尽量一开始就把 collation 给设置对。</p>
<h2 id="索引"><strong>索引</strong></h2>
<p>OceanBase 里的索引和纯 AP 数据库的索引可能还不太一样,在一个 table scan 算子里,对同一张表进行谓词过滤,只能用到一个索引。<strong>所以建议就是按需建索引,尽量别像其他纯 AP 数据库一样,大量创建(不必要的)索引。</strong></p>
<p>OB 正在支持 index merge 的能力,这个能力会对查询谓词进行拆分,将每部分谓词使用不同的索引进行 index range scan,随后合并各个索引表的扫描结果,再统一进行回表。当查询中各个索引的过滤性不强,但联合过滤性强时,会有较大的性能优势。</p>
<p>其实现在的版本已经支持通过 UNION_MERGE Hint 来进行 index merge 了,不过随着 AP 业务的不断拓展,马上还会支持更常用的多个全文索引和二级索引的 index merge。</p>
<h2 id="colocate--tablegroup"><strong>colocate / tablegroup</strong></h2>
<p>一些 AP 数据库在打散数据时,支持更细粒度地去调整数据在不同节点的分布情况。例如 StarRocks 支持通过 colocate_with,可以将两张或多张表的分区分布规则设置为一致,从而在分布式查询中显著减少数据重分布的开销,提升 Join 查询性能。</p>
<p>另一些纯 AP 数据库,并不支持这个能力,大多都是非常简单的 distributed by 分布键,不过只要能保持 hash 分区规则和分片数一致,基本都能保证分布规则是一样的。</p>
<p>在 OceanBase 中,可以通过 <strong>tablegroup</strong><sup><strong></strong></sup> 来替换类似于 colocate_with 的能力。tablegroup 也是用来调整一批表的分区分布规则,让查询中尽量少一些数据在网络中的重分布,使得计划中出现更多的 partition wise join。</p>
<h2 id="复杂数据类型"><strong>复杂数据类型</strong></h2>
<p>AP 场景常用的复杂数据类型是 json、bitmap、array、string,这些 OceanBase 都支持了,直接平迁就行,所以先略过不提。</p>
<h2 id="聚合表"><strong>聚合表</strong></h2>
<p>目前只有 StarRocks 有这个 Aggregation Table,在 OceanBase 中,可以用物化视图来代替。</p>
<h2 id="最小迁移单位"><strong>最小迁移单位</strong></h2>
<p>各家数据库在这里一般都只是名字不同,有的叫 shard,有的叫 segment,有的叫 share storage,其实不必细究。OceanBase 中的最小迁移单位,在逻辑上叫 partition,partition 对应的物理分片叫 tablet,了解即可。</p>
<h2 id="ap-场景表结构设计总结"><strong>AP 场景表结构设计总结</strong></h2>
<p>OceanBase AP 场景的表结构设计考虑项:</p>
<ol>
<li>数据聚集纬度:通常按时间,部分场景按用户 ID。个别场景还得考虑增量数据对合并的影响,例如可以通过设置时间维度的聚集,尽量将增量数据聚集到一起,这样可以增加查询效率和提升合并速度。</li>
<li>行存 / 列存:尽量与原系统保持一致,识别出特殊场景再做不一致设计。</li>
<li>增量数据:如果是按照时间维度进行分区,并且主要更新最近的数据,那么应该尽量将增量数据聚集到一起。如果原表没有分区,还可通过 hash 分区将增量打散到多机,充分利用多机性能。</li>
<li>分区:列存会增加分区内数据管理的复杂度,相比行存更应采用更少的分区数。AP 场景建议:hash 分区数设置为单 zone cpu 数的一半,单机分区数不宜超过 10 万,单分区行数不宜小于 100 万。</li>
<li>table mode:识别出来的 buffer 表采用 queue 表模式。</li>
<li>collation:尽量使用 utf8mb4_binary,替换后性能一般可提升 20% ~ 30%。</li>
<li>索引:AP 场景尽量不使用建索引优化,根据原系统已有的索引,可按需创建少量必要的索引。</li>
<li>复制表:会影响写入性能,按需来。</li>
</ol>
<h1 id="行存--列存各自的优势"><strong>行存 / 列存各自的优势</strong></h1>
<p><img alt="" loading="lazy" src="https://intranetproxy.alipay.com/skylark/lark/0/2025/png/32756313/1751874242214-3632c8bd-8847-4a50-a5d3-91b300e1ef5c.png" class="lazyload"></p>
<p>列存的实现只要知道这两点:</p>
<ul>
<li>只有基线数据(major sstable)是列存。增量数据 memtable、转储的 sstable 都是行存。</li>
<li>行列混存时,会共用行存增量数据。</li>
</ul>
<p>列存优势:</p>
<ul>
<li>大宽表只扫描部分列,省了 IO。</li>
<li>压缩率高 (相比行存)。</li>
<li>默认就有 skip index,可以快速过滤(行存需要手动去创建)。</li>
</ul>
<p>行存优势:</p>
<ul>
<li>适合点查 / 小范围扫描 (insert on duplicate update、索引回表、NLJ 等需要拿到完整行数据的操作)</li>
<li>可以通过 row cache 加速查询。</li>
<li>合并快(合并时不需要对增量数据和基线数据进行行列格式互转)。列存可适当调大合并线程数 merge_thread_count。同时也需关注IO,例如可以考虑把 _io_read_batch_size 调大,把 _io_read_redundant_limit_percentage 调小。</li>
</ul>
<p>To be continue:</p>
<p>行存 / 列存这个话题太大了,这次就先说几个最基础的点,其他会专门放在下一篇 PoC 学习笔记里来细说。</p>
<h1 id="增量数据常见问题"><strong>增量数据常见问题</strong></h1>
<p>常见问题:</p>
<ol>
<li>如果增量数据分布很散,导致所有基线数据都要跟着改,就会造成比较严重的写入放大问题。叠加列存合并慢问题,会导致合并时间过长。如果是时间维度组织和更新的表,一般不会有问题。</li>
<li>增量数据本身查询慢:单行,无下压,无编码。如果增量数据都是内存里的还好,如果增量数据有转储的 sstable,因为是行存,可能会有行列互转的开销,而且还会有额外的 IO 开销。</li>
<li>查询 “拖累”:这个是影响最大的。例如一行增量可能会拖累前后 100 ~ 1000 行的查询性能。因为微块里只要有一行数据做了修改,整个微块的查询可能就会退化成单行迭代的方式,性能会受到影响。这个问题很快会被优化掉。</li>
</ol>
<p>解决方式:</p>
<ol>
<li>通过选择 range 分区大小,控制写入放大范围。比如原来按月分区,在 OceanBase 中,可能可以通过调整成按周分区,来减少写放大的影响。</li>
<li>原来没有分区的表,在 OceanBase 中可以考虑通过 hash 分区将增量数据打散到多机,充分利用多机的硬件资源。</li>
<li>调整 table mode 加快合并,增量数据尽量在合并完成之后再查询。</li>
<li>调整数据聚集方式,将增量数据聚集到一起,避免查询处处被“拖累”。</li>
</ol>
<h1 id="oceanbase-ap-场景-poc-总结"><strong>OceanBase AP 场景 PoC 总结</strong></h1>
<p>以下内容适用于 OceanBase 435 bp2 版本</p>
<ul>
<li>选择 OLAP 租户模板,默认:列存,堆表,auto dop,ubf8mb4_binary,关 NLJ 等。</li>
<li>原库中有 clustered key / clustering_key / ordery by 等聚集索引时,通常来说,就不是以时间维度聚集的了。需要使用索引组织表(不能用堆表),设计主键达到类似效果。</li>
<li>行存 / 列存与原系统保持一致,例如 MySQL 迁过来用行存,某某纯 AP 数据库迁过来用列存,MySQL + 某某 AP 数据库迁过来用行列混存(后面的 PoC 学习笔记里会细说)。</li>
<li>分区优先考虑:堆表 + 时间列 range 一级分区 + 业务 hash 二级分区。否则要根据数据聚集维度和常用查询语句来设计分区。</li>
<li>collation 尽量用 utf8mb4_bin。</li>
<li>增量问题:将增量数据聚集到一起 + table mode 调整。</li>
<li>空间换时间:按需少量索引 + 物化视图。</li>
<li>旁路导入:旁路导入会加表锁,会影响 DML 操作(后面的 PoC 学习笔记里会细说)。</li>
</ul>
<p>💌</p>
<blockquote>
<p>老纪的技术唠嗑局 不仅希望能持续给大家带来有价值的技术分享,也希望能和大家一起为开源社区贡献力量。如果你对 OceanBase 开源社区认可,点亮一颗小星星 ✨ 吧!你的每一个Star,都是我们努力的动力~💕<br>
https://github.com/oceanbase/oceanbase</p>
</blockquote><br><br>
来源:https://www.cnblogs.com/OBCE666/p/18971312
頁:
[1]