【OceanBase 系列】—— OceanBase v4.3 特性解读:查询性能提升之利器列存储引擎

原文链接:OceanBase 社区

 

对于分析类查询,列存可以极大地提升查询性能,也是 OceanBase 做好 HTAP 和 OLAP 的一项不可缺少的特性。本文介绍 OceanBase 列存的实现特色。

OceanBase从诞生起就一直坚持LSM-Tree架构,不断打磨功能支持了各类典型的 TP 类型业务,持续优化性能满足各种极限负载压力,积累了大量工程实践经验,打造出一套纯自主研发且有充分特色的业界领先LSM-tree 存储引擎。常见的 OLAP 场景往往是批量写入,不会有大量随机更新,尽量保证列存组织数据是静态的,这种场景天然适合 LSM-Tree 架构。

在4.3版本,基于原有技术积累,OceanBase 存储引擎继续扩展,实现对列存的支持,实现存储一体化,一套代码一个架构一个OBServer,列存数据和行存数据完美共存,这样真正实现了对TP类和AP类查询的性能的兼顾。

整体架构

OceanBase作为原生分布式数据库,用户数据默认会多副本存储,为了利用多副本的优势,为用户提供数据强校验以及迁移数据重用等进一步的增强体验,自研的LSM-Tree存储引擎也做了较多的针对性设计,首先每个用户数据整体可以分成两个大部分基线数据和增量数据。

  • 基线数据。不同于其它主流LSM-Tree数据库,OceanBase利用分布式多副本的基础,提出'每日合并'的概念,租户会定期或者根据用户操作选择一个全局版本号,租户数据的所有副本均以这个版本完成一轮Major Compaction,最后生成这个版本的基线数据,所有副本同一个版本的基线数据物理完全一致。
  • 增量数据。相对基线数据而言,用户数据在最新版本的基线数据之后所有写入数据均属于增量数据,具体来说,增量数据可以是用户刚写入Memtable的内存数据,也可以是已经转储为SSTable的磁盘数据。 对于用户数据的所有副本来说,增量数据各个副本独立维护,不保证一致,并且不同于基线数据基于指定版本生成,增量数据包含所有多版本数据。

基于列存应用场景随机更新量可控的背景,OceanBase结合自身基线数据和增量数据的特质,提出了一套对上层透明的列存实现方式

  • 基线数据存储为列存模式,增量数据保持行存,用户所有 DML 操作不受影响,上下游同步无缝接入,列存表数据仍然可以像行存表一样进行所有事务操作。
  • 列存模式下每列数据存储为一个独立SSTable,所有列的SSTable组合成为一个虚拟SSTable作为用户的列存基线数据,如下图所示。
  • 根据用户建表指定设置,基线数据可以有行存,列存,行存列存冗余三种模式。

1715138557

我们不仅在存储引擎中实现了列存模式,为了让用户能够更容易从其它 OLAP 数据库迁移过来,以及帮助之前有 OLAP 需求的 OceanBase 老客户升级到列存,从优化器到执行器以及存储其它相关模块,都针对列存进行了适配以及优化,让用户迁移到列存后基本对业务无感,能够像使用行存一样享受到列存带来的性能优势。 也让OceanBase真正实现了TP/AP一体化,实现一套引擎一套代码支持不同类型业务的目标,打造完善的HTAP引擎。

1715138569

  • SQL一体化
    • 为列存设计实现了新的代价模型,并增加列存相关统计信息,优化器根据数据表存储模式根据代价自动选择计划。
    • 实现新的向量化引擎,完成关键算子的新引擎重构,不同类型计划根据代价自适应选择向量化以及批大小。
  • 存储一体化
    • 用户数据根据表模式指定,可以根据业务负载类型灵活设置为列存行存或者行列冗余模式,用户查询/备份恢复等操作完全透明。
    • 列存表完整支持所有在线及离线DDL操作,完整支持所有数据类型及二级索引创建,保证用户使用方法和行存别无二致。
  • 事务一体化
    • 增量数据全部为行存,事务内修改、日志内容以及多版本控制等和行存完全共享逻辑。

核心特性

特性1:自适应Compaction

引入新的列存存储模式之后,数据合并行为和原有行存数据有较大变化,由于增量数据全部是行存,需要和基线数据合并后拆分到每个列的独立SSTable中,合并时间和资源占用相对行存会有较大增长.

为了加速列存表合并速度,Compaction流程进行大幅增强,对于列存表,除了能够像行存表一样进行水平拆分并行合并加速之外,还增加了垂直拆分加速,列存表会降多个列的合并动作放在一个合并任务内进行,并且一个任务内的列数能够根据系统资源自主选择升降,保证整体在合并速度以及内存开销达到更好的平衡。

特性2:列式编码算法

OceanBase一直以来存储数据会经过两级压缩,第一级是OceanBase自研的行列混合编码压缩,第二级是通用压缩,其中行列混合编码由于是数据库内置算法,因此可以支持不解压直接查询,同时可以利用编码信息进行查询过滤加速,尤其对AP类查询会有极大的加速。

但是原有行列混合编码算法仍然偏向行组织,因此针对列存表实现了全新的列式编码算法,相比原有编码算法,新算法支持查询的全面向量化执行,支持兼容不同指令集的SIMD优化,同时针对数值类型大幅提高压缩比,实现对原有算法在性能和压缩比上的全面提升。

特性3:Skip Index

常见列存数据库一般均会对每列数据按照一定的粒度进行预聚合计算,聚合的结果随数据一起持久化,当用户查询请求访问列数据时,数据库能够通过预聚合数据过滤数据,大幅减少数据访问开销,减少不必要的IO消耗。

在列存引擎中,我们同样增加了skip index的支持,针对每列数据会按照微块粒度进行最大值、最小值、和以及null总量等多个维度的聚合计算,并逐层向上聚合累加获得宏块、SSTable等更大粒度的聚合值,用户查询能够根据扫描范围不断下钻选取合适粒度聚合值进行过滤以及聚合输出。

特性4:查询下压

OceanBase 在3.2版本开始初步支持简单的查询下压,从4.x版本开始存储全面支持了向量化以及更多的下压支持,在列存引擎中,下压功能进一步得到增强和扩展,具体包括:

  • 所有查询filter下压,同时根据filter类型,能够进一步利用skip index以及编码信息加速。
  • 常用聚合函数的下压,非group by场景下,目前count/max/min/sum/avg等聚合函数已能下压到存储引擎.
  • group by下压,在NDV较少的列上,支持group by下压存储计算,利用微块内字典信息进行大幅加速。

使用列存

默认创建列存表

对于 OLAP 业务,我们推荐默认创建列存表。如何让租户创建出来的表默认就是列存表?通过下面的配置项即可实现:

alter system set default_table_store_format = "column";

随后我们创建的表格没有指定 column group 时,默认就是列存表。

OceanBase(root@test)>create table  t1 (c1 int primary key, c2 int ,c3 int);
Query OK,0 rows affected (0.301 sec)OceanBase(root@test)>show create table t1;CREATE TABLE `t1` (`c1` int(11) NOT NULL,`c2` int(11) DEFAULT NULL,`c3` int(11) DEFAULT NULL,PRIMARY KEY (`c1`)
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
WITH COLUMN GROUP(each column)1 row in set (0.101 sec)
指定创建列存表

列存引入新的语法with column group,当用户建表时最后指定 with column group(each column) 即代表创建列存表。

OceanBase(root@test)>create table  tt_column_store (c1 int primary key, c2 int ,c3 int) with column group (each column);
Query OK,0 rows affected (0.308 sec)OceanBase(root@test)>show create table tt_column_store;CREATE TABLE `tt_column_store` (`c1` int(11) NOT NULL,`c2` int(11) DEFAULT NULL,`c3` int(11) DEFAULT NULL,PRIMARY KEY (`c1`)
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 WITH COLUMN GROUP(each column)1 row in set (0.108 sec)
指定创建列存行存冗余表

对于部分场景,用户可以忍受一定程度的数据冗余,希望带来AP/TP业务场景的兼顾,此时可以增加行存数据的冗余,通过with column group语法增加指定all columns即可。

create table  tt_column_row (c1 int primary key, c2 int , c3 int) with column group (all columns, each column);
Query OK, 0 rows affected (0.252 sec)OceanBase(root@test)>show create table tt_column_row;
CREATE TABLE `tt_column_row` (`c1` int(11) NOT NULL, `c2` int(11) DEFAULT NULL, `c3` int(11) DEFAULT NULL, PRIMARY KEY (`c1`)
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 WITH COLUMN GROUP(all columns, each column)1 row in set (0.075 sec)
列存扫描

如何查看是否列存扫描计划?

计划展示上新增COLUMN TABLE FULL SCAN,描述列存表的范围扫描

OceanBase(root@test)>explain select * from tt_column_store;
+--------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                             |
+--------------------------------------------------------------------------------------------------------+
| =================================================================                                      |
| |ID|OPERATOR              |NAME           |EST.ROWS|EST.TIME(us)|                                      |
| -----------------------------------------------------------------                                      |
| |0 |COLUMN TABLE FULL SCAN|tt_column_store|1       |7           |                                      |
| =================================================================                                      |
| Outputs & filters:                                                                                     |
| -------------------------------------                                                                  |
|   0 - output([tt_column_store.c1], [tt_column_store.c2], [tt_column_store.c3]), filter(nil), rowset=16 |
|       access([tt_column_store.c1], [tt_column_store.c2], [tt_column_store.c3]), partitions(p0)         |
|       is_index_back=false, is_glOceanBaseal_index=false,                                                      |
|       range_key([tt_column_store.c1]), range(MIN ; MAX)always true                                     |
+--------------------------------------------------------------------------------------------------------+

计划展示上新增COLUMN TABLE GET,描述列存表上的指定主键的get操作

OceanBase(root@test)>explain select * from tt_column_store where c1 = 1;
+--------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                             |
+--------------------------------------------------------------------------------------------------------+
| ===========================================================                                            |
| |ID|OPERATOR        |NAME           |EST.ROWS|EST.TIME(us)|                                            |
| -----------------------------------------------------------                                            |
| |0 |COLUMN TABLE GET|tt_column_store|1       |14          |                                            |
| ===========================================================                                            |
| Outputs & filters:                                                                                     |
| -------------------------------------                                                                  |
|   0 - output([tt_column_store.c1], [tt_column_store.c2], [tt_column_store.c3]), filter(nil), rowset=16 |
|       access([tt_column_store.c1], [tt_column_store.c2], [tt_column_store.c3]), partitions(p0)         |
|       is_index_back=false, is_global_index=false,                                                      |
|       range_key([tt_column_store.c1]), range[1 ; 1],                                                   |
|       range_cond([tt_column_store.c1 = 1])                                                             |
+--------------------------------------------------------------------------------------------------------+
12 rows in set (0.051 sec)

如何通过hint指定列存行存冗余表走列存扫描?

对于列存行存冗余表,优化器会根据代价选择走行存或者列存扫描,如简单场景做全表扫描,会默认使用行存生成计划

OceanBase(root@test)>explain select * from tt_column_row;
+--------------------------------------------------------------------------------------------------+
| Query Plan                                                                                       |
+--------------------------------------------------------------------------------------------------+
| ========================================================                                         |
| |ID|OPERATOR       |NAME         |EST.ROWS|EST.TIME(us)|                                         |
| --------------------------------------------------------                                         |
| |0 |TABLE FULL SCAN|tt_column_row|1       |3           |                                         |
| ========================================================                                         |
| Outputs & filters:                                                                               |
| -------------------------------------                                                            |
|   0 - output([tt_column_row.c1], [tt_column_row.c2], [tt_column_row.c3]), filter(nil), rowset=16 |
|       access([tt_column_row.c1], [tt_column_row.c2], [tt_column_row.c3]), partitions(p0)         |
|       is_index_back=false, is_global_index=false,                                                |
|       range_key([tt_column_row.c1]), range(MIN ; MAX)always true                                 |
+--------------------------------------------------------------------------------------------------+

此时如果用户还是希望手动调优,走列存扫描,可以通过hint USE_COLUMN_TABLE来强制tt_column_row 表走列存扫描

OceanBase(root@test)>explain select /*+ USE_COLUMN_TABLE(tt_column_row) */ * from tt_column_row;
+--------------------------------------------------------------------------------------------------+
| Query Plan                                                                                       |
+--------------------------------------------------------------------------------------------------+
| ===============================================================                                  |
| |ID|OPERATOR              |NAME         |EST.ROWS|EST.TIME(us)|                                  |
| ---------------------------------------------------------------                                  |
| |0 |COLUMN TABLE FULL SCAN|tt_column_row|1       |7           |                                  |
| ===============================================================                                  |
| Outputs & filters:                                                                               |
| -------------------------------------                                                            |
|   0 - output([tt_column_row.c1], [tt_column_row.c2], [tt_column_row.c3]), filter(nil), rowset=16 |
|       access([tt_column_row.c1], [tt_column_row.c2], [tt_column_row.c3]), partitions(p0)         |
|       is_index_back=false, is_global_index=false,                                                |
|       range_key([tt_column_row.c1]), range(MIN ; MAX)always true                                 |
+--------------------------------------------------------------------------------------------------+

类似的,通过hint NO_USE_COLUMN_TABLE可以强制表不走列存扫描

OceanBase(root@test)>explain select  /*+ NO_USE_COLUMN_TABLE(tt_column_row) */ c2 from tt_column_row;
+------------------------------------------------------------------+
| Query Plan                                                       |
+------------------------------------------------------------------+
| ========================================================         |
| |ID|OPERATOR       |NAME         |EST.ROWS|EST.TIME(us)|         |
| --------------------------------------------------------         |
| |0 |TABLE FULL SCAN|tt_column_row|1       |3           |         |
| ========================================================         |
| Outputs & filters:                                               |
| -------------------------------------                            |
|   0 - output([tt_column_row.c2]), filter(nil), rowset=16         |
|       access([tt_column_row.c2]), partitions(p0)                 |
|       is_index_back=false, is_global_index=false,                |
|       range_key([tt_column_row.c1]), range(MIN ; MAX)always true |
+------------------------------------------------------------------+
11 rows in set (0.053 sec)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8657.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2020 年国考【计算机专业】真题及答案

真题及答案 第一部分数学基础课程 一、(共 5 分)用逻辑符号表达下列语句(论域为包含一切事物的合集) (2 分)确诊者并不都有症状(注:需给出两种形式表达, 一种用存在量词, 一种用全称…

python魔法方法是什么

魔法方法是python内置方法,不需要主动调用,存在的目的是为了给python的解释器进行调用,几乎每个魔法方法都有一个对应的内置函数,或者运算符,当我们对这个对象使用这些函数或者运算符时就会调用类中的对应魔法方法&…

MVC与MVVM架构模式

1、MVC MVC:Model-View-Controller,即模型-视图-控制器 MVC模式是一种非常经典的软件架构模式。从设计模式的角度来看,MVC模式是一种复合模式,它将多个设计模式结合在一种解决方案中,从而可以解决许多设计问题。 MV…

【3D目标检测】常见相关指标说明

一、mAP指标 mean Average Precision(平均精度均值),它是目标检测和信息检索等任务中的重要性能指标。mAP 通过综合考虑精度和召回率来衡量模型的总体性能。 1.1 精度(Precision) 表示检索到的目标中实际为正确目标…

Spring Task及订单状态定时处理

1:Spring Task概念: Spring Task 是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑 定时任务的理解 定时任务即系统在特定时间执行一段代码,它的场景应用非常广泛: 购买游戏的月卡会员后&a…

Centos7网络处理name or service not known

1、编辑->虚拟网络编辑器 2、查看本机的ip 3、 /etc/sysconfig/network-scripts/ 查看文件夹下面的 ifcfg-eth33 后面的33可能不一样 vi /etc/resolv.conf 编辑文件添加以下DNS nameserver 114.114.114.114 4、设置本机的网络 5、ping www.baidu.com 先重启…

第50期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

全双工音频对讲模块-支持空中升级、多级无线中继

SA618F30是一款高集成的大功率全双工无线音频模块,发射功率高达32dBm。该音频模块简化接口,只需外接音频功放或麦克风即可作为一个小型对讲机,方便快捷嵌入到各类手持设备中。支持多级无线中继,支持OTA空中升级。 SA618F30配备1W…

Java快速入门系列-11(项目实战与最佳实践)

第十一章:项目实战与最佳实践 11.1 项目规划与需求分析项目规划需求分析实例代码 11.2 系统设计考虑实例代码 11.3 代码实现与重构实例代码 11.4 性能优化与监控实例代码 11.5 部署与持续集成/持续部署(CI/CD)实例代码 11.1 项目规划与需求分析 在进行任何软件开发…

Hikyuu-PF-银行股轮动交易策略实现

今天,带来的是“如何使用 Hikyuu 中的投资组合来实现银行股轮动交易策略”。 这个策略的逻辑很简单:持续持有两支市净率最低银行股,然后每月换仓 定义回测周期与回测标的 同样,首先定义回测周期: # 定义回测日期 …

了解内存函数

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱博客 所属栏目&#xff1a;C语言 前言 内存函数不止malloc、calloc、realloc、free还有memcpy、memmove、memset、memcmp。前四个的头文件是<stdlib.h>,后四个的头文件是<strin…

Ansible----playbook模块之templates模块、tags模块、roles模块

目录 引言 一、templates模块 &#xff08;一&#xff09;关键信息 &#xff08;二&#xff09;实际操作 1.定义主机组 2.设置免密登录 3.分别建立访问目录 4.定义模板文件 5.创建playbook文件 6.执行剧本 7.验证结果 二、tags模块 &#xff08;一&#xff09;创建…

《QT实用小工具·六十一》带动画的三角形指示箭头

1、概述 源码放在文章末尾 该项目实现了一个带动画效果的三角形指示箭头&#xff0c;项目demo演示如下所示&#xff1a; 用法 interestingindicate.h interestingindicate.cpp 放到工程中&#xff0c;直接使用即可。 注意&#xff1a;建议绝对布局&#xff0c;手动指定 wid…

华为车BU迈入新阶段,新任CEO对智能车的3个预判

作者 |张马也 编辑 |德新 4月24日&#xff0c;北京车展前夕&#xff0c;华为召开了新一年的智能汽车解决方案新品发布会。 这次发布会&#xff0c;也是华为智能汽车解决方案BU&#xff08;简称「车BU」&#xff09;CEO 靳玉志的公开首秀。 一开场&#xff0c;靳玉志即抛出了…

BACnet转MQTT网关智联楼宇json格式自定义

智能建筑的BACnet协议作为楼宇自动化领域的通用语言&#xff0c;正逐步迈向更广阔的物联网世界。随着云计算和大数据技术的飞速发展&#xff0c;如何将BACnet设备无缝融入云端生态系统&#xff0c;成为众多楼宇管理者关注的焦点。本文将以一个实际案例&#xff0c;揭示BACnet网…

Clion STM32CubeMX 项目

系列文章目录 前言 最后修改 2024 年 4 月 16 日 操作系统&#xff1a;Windows / Linux / macOS 所需工具 STM32CubeMX、GNU ARM 工具链 项目格式&#xff1a; CMake 兼容配置&#xff1a; OpenOCD 运行与调试/嵌入式 GDB 服务器 对于以 STM32 板卡为目标的嵌入式项目&#xf…

分布式与一致性协议之ZAB协议(七)

ZAB协议 ZAB协议:如何处理读写请求 你应该有这样的体会&#xff0c;如果你想了解一个网络服务&#xff0c;执行的第一个功能肯定是写操作&#xff0c;然后才会执行读操作。比如&#xff0c;你要了解ZooKeeper&#xff0c;那么肯定会在zkClient.sh命令行中执行写操作(比如crea…

如何购买阿里云99计划的ECS云服务器?99元购买阿里云2核2G3M服务器教程

阿里云助力中小企业和开发者无忧上云的“99计划”中有两款性价比超高的ECS云服务器&#xff0c;2026年3月31日活动结束前新购和续费价格一样。 其中个人和企业新老用户同享的2核2G3M服务器仅需99元/年&#xff08;续费同价&#xff09;&#xff0c;企业新老用户同学的2核4G5M仅…

Python 框架安全:Django SQL注入漏洞测试.(CVE-2021-35042)

什么是 Django 框架 Django 是一个用 Python 编写的 Web 应用程序框架。它提供了许多工具和库&#xff0c;使得开发 Web 应用程序变得更加容易和高效。Django 遵循了“MTV”&#xff08;模型-模板-视图&#xff09;的设计模式&#xff0c;将应用程序的不同组件分离开来&#x…

《从零开始,搭建一个简单的UVM验证平台》实操

最近的工作中需要用UVM平台去仿真软件同事写的C程序&#xff0c;虽然只要用EDA同事已经搭好的UVM平台稍微改改就行&#xff0c;但对于我这种从未接触过UVM甚至都没用过System Verilog的纯FPGA工程师来说还是很有难度的&#xff0c;因为我对这方面一点概念都没有。 基于此&…