写点什么

AP 引擎助力加速生产 SQL 运行

作者:GreatSQL
  • 2024-02-23
    福建
  • 本文字数:7589 字

    阅读完需:约 25 分钟

Rapid 存储引擎简介

从 GreatSQL 8.0.32-25 版本开始,新增 Rapid 存储引擎,该引擎使得 GreatSQL 能满足联机分析(OLAP)查询请求。


Rapid 引擎采用插件(Plugin)方式嵌入 GreatSQL 中,可以在线动态安装或卸载。


Rapid 引擎不会直接面对客户端和应用程序,用户无需修改原有的数据访问方式。它是一个无共享、内存化、混合列式存储的查询处理引擎,其设计目的是为了高性能的处理分析型查询。


并且在 TPC-H 性能表现优异在 32C64G 测试机环境下,TPC-H 100G 测试中 22 条 SQL 总耗时仅需不到 80 秒



下面是几个不同 TPC-H 数据量级的压缩率数据:



经过 GreatSQL 社区的测试分析可以看出,相较于 InnoDB 存储引擎,Rapid 存储引擎在存储效率上获得了极大提升。在存放相同的数据集时,Rapid 的数据文件所需要的空间仅为 InnoDB 的 6~7 分之 1,大约**降低了 85%**左右。

真实生产案例测试

为了全面验证 AP 引擎的性能提升,我们成功获取了真实生产环境下的 SQL 语句、表结构以及经过脱敏处理的数据。在此,特别感谢潲同学和贵司的协助!

测试环境介绍

本次测试采用的环境是 Arch Linux x86_64,机器配置为 12C15G


$ uname -aLinux myarch 6.6.3-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 29 Nov 2023 00:37:40 +0000 x86_64 GNU/Linux$ cat /proc/cpuinfo | grep "processor" | wc -l12$  free -h     totalMem: 15Gi
复制代码


采用的 GreatSQL 版本为 GreatSQL 8.0.32-25 版本


$ mysql --version           mysql  Ver 8.0.32-25 for Linux on x86_64 (GreatSQL, Release 25, Revision 79f57097e3f)
复制代码

真实生产 SQL

展示即将进行测试的生产 SQL(这里不深入讨论该 SQL 是否存在优化的可能性):


select c.id, c.dept_id, c.user_id, c.type, c.source, c.charge_no, c.amount, c.from_bank, c.to_bank, c.receipt,c.status, c.remark, c.create_by, c.create_time, c.update_by, c.update_time,c.reason,c.fr_no, d.dept_name, dt.company_name, cp.company_name  from charge cleft join dept d on c.dept_id = d.dept_idleft join user u on c.user_id = u.user_idleft join dept_tax dt on c.dept_id = dt.dept_idleft join dept_info di on c.dept_id = di.dept_idleft join company_bank cb on di.sign_cbid = cb.idleft join company cp on cb.company_id = cp.company_idlimit 3313445,10;
复制代码

真实生产表结构

生产 SQL 涉及 7 张表,我们将逐一展示每张表的表结构。为了保护隐私,我们对部分字段进行了脱敏处理以及一些微调


dept 表


CREATE TABLE `dept` (  `dept_id` bigint(20) NOT NULL AUTO_INCREMENT,  `parent_id` bigint(20) DEFAULT '0',  `ancestors` varchar(50) DEFAULT '',  `dept_name` varchar(30) DEFAULT '',......  `create_time` datetime DEFAULT NULL,  `update_by` varchar(64) DEFAULT '',  `update_time` datetime DEFAULT NULL,  PRIMARY KEY (`dept_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表'
复制代码


user 表


CREATE TABLE `user` (  `user_id` bigint(20) NOT NULL AUTO_INCREMENT,  `dept_id` bigint(20) DEFAULT NULL,  `fans_id` bigint(20) DEFAULT NULL,  `login_name` varchar(30) NOT NULL,  `user_name` varchar(30) NOT NULL,  `alias` varchar(100) DEFAULT NULL,  `user_type` varchar(2) DEFAULT '00',  `email` varchar(50) DEFAULT '',  `phonenumber` varchar(11) DEFAULT '',  `sex` char(1) DEFAULT '0',......  `create_by` varchar(64) DEFAULT '',  `create_time` datetime DEFAULT NULL,  `update_by` varchar(64) DEFAULT '',  `update_time` datetime DEFAULT NULL,  `remark` varchar(500) DEFAULT NULL,  PRIMARY KEY (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'
复制代码


dept_tax 表


CREATE TABLE `dept_tax` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `dept_id` bigint(20) NOT NULL,  `company_name` varchar(50) NOT NULL,  `tax_no` varchar(50) DEFAULT NULL,  `tax_type` varchar(30) DEFAULT NULL,......  `create_by` varchar(50) DEFAULT '',  `create_time` datetime DEFAULT NULL,  `update_by` varchar(50) DEFAULT '',  `update_time` datetime DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='信息表'
复制代码


dept_info 表


CREATE TABLE `dept_info` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `dept_id` bigint(20) NOT NULL,  `customer_id` bigint(20) DEFAULT NULL,  `dept_type` char(1) DEFAULT '1',  `industry_type` char(1) DEFAULT '0',  `dept_flag` char(1) DEFAULT '1',  `dept_kind` char(1) DEFAULT '0',  `bus_scope` varchar(10) DEFAULT '1',  `channel_id` bigint(20) DEFAULT NULL,......   PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='信息表'
复制代码


company_bank 表


CREATE TABLE `company_bank` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `company_id` bigint(20) DEFAULT NULL,  `bank_name` varchar(50) DEFAULT NULL,  `bank_card` varchar(30) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
复制代码


company 表


CREATE TABLE `company` (  `company_id` bigint(20) NOT NULL AUTO_INCREMENT,  `company_name` varchar(100) DEFAULT NULL,  PRIMARY KEY (`company_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
复制代码


charge 表


CREATE TABLE `charge` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `dept_id` bigint(20) NOT NULL,  `user_id` bigint(20) DEFAULT NULL,  `type` char(1) DEFAULT NULL,......  `create_time` datetime DEFAULT NULL,  `update_by` varchar(50) DEFAULT '',  `update_time` datetime DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
复制代码


不深入探讨 SQL 和表结构是否存在优化的可能性,只验证 AP 引擎提升查询测试。

加载数据

鉴于原始数据较为有限,为了更明显地进行测试,我们为每张表生成了一些新数据,来看下各表数据和表空间大小是多少:


未改造测试

待测试的 SQL 语句:


select c.id, c.dept_id, c.user_id, c.type, c.source, c.charge_no, c.amount, c.from_bank, c.to_bank, c.receipt,c.status, c.remark, c.create_by, c.create_time, c.update_by, c.update_time,c.reason,c.fr_no, d.dept_name, dt.company_name, cp.company_name  from _charge cleft join dept d on c.dept_id = d.dept_idleft join user u on c.user_id = u.user_idleft join dept_tax dt on c.dept_id = dt.dept_idleft join dept_info di on c.dept_id = di.dept_idleft join company_bank cb on di.sign_cbid = cb.idleft join company cp on cb.company_id = cp.company_idlimit 3313445,10;
复制代码


先不使用 AP 引擎测试查询五次:



可以看到五次测试结果都是稳定在 12 秒左右,平均耗时 12.64/s:


使用 Rapid 引擎测试

启用 Rapid 引擎

greatsql> INSTALL PLUGIN Rapid SONAME 'ha_rapid.so';
greatsql> SHOW PLUGINS;+----------------------------------+----------+--------------------+----------------------+---------+| Name | Status | Type | Library | License |+----------------------------------+----------+--------------------+----------------------+---------+| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |...| Rapid | ACTIVE | STORAGE ENGINE | ha_rapid.so | GPL |+----------------------------------+----------+--------------------+----------------------+---------+55 rows in set (0.00 sec)
复制代码

加上 Rapid 辅助引擎

greatsql> ALTER TABLE dept SECONDARY_ENGINE = rapid;Query OK, 0 rows affected (0.02 sec)Records: 0  Duplicates: 0  Warnings: 0greatsql> ALTER TABLE user SECONDARY_ENGINE = rapid;greatsql> ALTER TABLE charge SECONDARY_ENGINE = rapid;greatsql> ALTER TABLE company SECONDARY_ENGINE = rapid;greatsql> ALTER TABLE company_bank SECONDARY_ENGINE = rapid;greatsql> ALTER TABLE dept_info SECONDARY_ENGINE = rapid;greatsql> ALTER TABLE dept_tax SECONDARY_ENGINE = rapid;
复制代码


查看建表 DDL,发现增加了 SECONDARY_ENGINE=rapid


greatsql> SHOW CREATE TABLE _company\G*************************** 1. row ***************************       Table: companyCreate Table: CREATE TABLE `company` (  `company_id` bigint NOT NULL AUTO_INCREMENT COMMENT '序号ID',  `company_name` varchar(100) DEFAULT NULL COMMENT '签约主体',  PRIMARY KEY (`company_id`)) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci SECONDARY_ENGINE=rapid1 row in set (0.00 sec)
复制代码

数据全量导入 Rapid 引擎中

greatsql> ALTER TABLE dept SECONDARY_LOAD;greatsql> ALTER TABLE user SECONDARY_LOAD;greatsql> ALTER TABLE charge SECONDARY_LOAD;greatsql> ALTER TABLE company SECONDARY_LOAD;greatsql> ALTER TABLE company_bank SECONDARY_LOAD;greatsql> ALTER TABLE dept_info SECONDARY_LOAD;greatsql> ALTER TABLE dept_tax SECONDARY_LOAD;
复制代码

开始测试 Rapid 引擎

有两种方式启用 Rapid 引擎


方式一


-- 设置use_secondary_engine=ON的时候,为保证查询语句能够使用rapid,-- 通常需要设置secondary_engine_cost_threshold = 0,或一个较小的阈值SET use_secondary_engine = ON;SET secondary_engine_cost_threshold = 0; 
复制代码


方式二(不建议)


-- 修改会话变量,设置强制使用Rapid引擎SET use_secondary_engine = FORCED;
-- 或执行SQL查询时指定HINTSELECT /*+ SET_VAR(use_secondary_engine=forced) */ ...省略 FROM from charge c;
复制代码


先使用方案二,执行 SQL 查询时指定 HINT 测试五次看看表现如何


待测试的 SQL 语句:


select /*+ SET_VAR(use_secondary_engine=forced) */ c.id, c.dept_id, c.user_id, c.type, c.source, c.charge_no, c.amount, c.from_bank, c.to_bank, c.receipt,c.status, c.remark, c.create_by, c.create_time, c.update_by, c.update_time,c.reason,c.fr_no, d.dept_name, dt.company_name, cp.company_namefrom _charge cleft join dept d on c.dept_id = d.dept_idleft join user u on c.user_id = u.user_idleft join dept_tax dt on c.dept_id = dt.dept_idleft join dept_info di on c.dept_id = di.dept_idleft join company_bank cb on di.sign_cbid = cb.idleft join company cp on cb.company_id = cp.company_idlimit 3313445,10;
复制代码


同样测试查询五次:



可以看到 Rapid 引擎出手即是秒杀,平均耗时 0.47/s:



改造前(平均耗时 12.64/s)和改造后(平均耗时 0.47/s)对比测试结果:



总体来说改造后约提升了 26.9 倍:



如果我们选择使用 HINT 进行改造,就需要对原 SQL 语句进行相应修改。因此,我们将采用方案一来进行试验


greatsql> SET use_secondary_engine = ON;greatsql> secondary_engine_cost_threshold = 0;# 查看下执行计划greatsql> explain select c.id, c.dept_id, c.user_id, c.type, c.source, c.charge_no, c.amount, c.from_bank, c.to_bank, c.receipt,c.status, c.remark, c.create_by, c.create_time, c.update_by, c.update_time,c.reason,c.fr_no , d.dept_name, dt.company_name, cp.company_name from charge c left join dept d on c.dept_id = d.dept_id left join user u on c.user_id = u.user_id left join dept_tax dt on c.dept_id = dt.dept_id left join dept_info di on c.dept_id = di.dept_id left join company_bank cb on di.sign_cbid = cb.id left join company cp on cb.company_id = cp.company_id limit 3313445,10\G*************************** 1. row ***************************           id: 1  select_type: SIMPLE        table: c   partitions: NULL         type: ALLpossible_keys: NULL          key: NULL      key_len: NULL          ref: NULL         rows: 905486     filtered: 100.00        Extra: Using secondary engine RAPID # 证明用到RAPID引擎# 下方省略,证明有用到RAPID引擎即可
复制代码


可以看到默认的使用了 RAPID 引擎

数据导入

在上方我们执行过ALTER TABLE xxx SECONDARY_LOAD这个操作,会将 InnoDB 主引擎中的数据全量加载到 Rapid 引擎中,这个过程称为全量导入。全量导入成功后,Rapid 引擎中的数据是静态的,当向主引擎表中继续插入、删除、修改数据时,并不会导入到 Rapid 引擎中。


那数据会更新会修改要怎么办呢?总不能每次都全量导入吧?


所以此时可以利用 binlog 特性,可以在全量导入成功后,启动增量导入任务。增量任务会读取自全量导入成功之后的 binlog 数据,将 binlog 解析并应用到 rapid 引擎中,这个过程称为增量导入


不同于全量导入,增量导入会启动一个常驻的后台线程,实时读取和应用增量 binlog 数据。

增量导入数据的限制和需求

在手册上有介绍到增量导入数据的限制和需求,如下:


  1. 需要设置表名大小写不敏感,即设置 lower_case_table_names = 1

  2. 需要开启 GTID 模式,即设置 gtid_mode = ONenforce_gtid_consistency = ON

  3. 需要采用 row 格式的 binlog event,不支持 statement 格式,即设置 binlog_format = ROW。增量任务运行过程中,检测到 statement 的 DML event,可能会报错退出。

  4. 需要关闭 GIPKs 特性,即设置 sql_generate_invisible_primary_key = OFF。用户表不能有 invisible primary key,如果表包含隐式不可见的主键,在全量导入过程中会报错;同时也不支持用户表中存在任何不可见列(invisible column)。

  5. 需要先对表执行过一次全量导入后,才能启动增量导入任务,否则任务启动会报错。

  6. 不支持 PARTIAL_UPDATE_ROWS_EVENT 类型的 binlog,即不要设置 binlog_row_value_options = PARTIAL_JSON

  7. 不支持 CREATE TABLE SELECT 语句,增量任务运行过程中,检测到该语句产生的 binlog event 时可能会报错退出。

  8. 不支持 XA 事务,运行过程中检查到 XA 事务会报错退出。

开启增量导入

增量导入有两个系统函数分别是


  • START_SECONDARY_ENGINE_INCREMENT_LOAD_TASK() :启动任务

  • STOP_SECONDARY_ENGINE_INCREMENT_LOAD_TASK():停止任务


执行 SQL 命令 SELECT START_SECONDARY_ENGINE_INCREMENT_LOAD_TASK() 即可启动增量任务,根据函数返回信息可以确认是否任务启动成功。如果启动失败,可以从错误日志中查看具体失败的原因。


该函数包含 3 个参数:


  • db_name,必选项,指定增量导入任务对应的数据库名。

  • table_name,必选项,指定增量导入任务对应的数据表名。

  • gtid,可选项,指定开始增量导入任务的起始 gtid_set 值。默认不需要指定,任务会自动根据ALTER TABLE ... SECONDARY_LOAD 全量导入时刻的 gtid_executed 进行计算和判断。


-- 对user表启动增量导入任务greatsql> SELECT START_SECONDARY_ENGINE_INCREMENT_LOAD_TASK('aptest', 'user');+------------------------------------------------------------------+| START_SECONDARY_ENGINE_INCREMENT_LOAD_TASK('aptest', 'user') |+------------------------------------------------------------------+| success                                                          |+------------------------------------------------------------------+1 row in set (0.00 sec)-- 查看增量导入任务状态greatsql>  SELECT * FROM information_schema.SECONDARY_ENGINE_INCREMENT_LOAD_TASK\G*************************** 1. row ***************************           DB_NAME: aptest        TABLE_NAME: user        START_TIME: 2024-02-21 09:33:55        START_GTID: 9548406d-8ff1-11ee-97ec-ec5c6826bca3:1-3808COMMITTED_GTID_SET: 9548406d-8ff1-11ee-97ec-ec5c6826bca3:1-3821         READ_GTID: 9548406d-8ff1-11ee-97ec-ec5c6826bca3:3821  READ_BINLOG_FILE: ./binlog.000023   READ_BINLOG_POS: 596312770             DELAY: 0            STATUS: RUNNING          END_TIME:               INFO: 1 row in set (0.00 sec)
复制代码


当然如果想停止也可以使用以下操作停止增量同步


greatsql>  SELECT STOP_SECONDARY_ENGINE_INCREMENT_LOAD_TASK('aptest', 'user');greatsql> SELECT STOP_SECONDARY_ENGINE_INCREMENT_LOAD_TASK('aptest', 'user');+-----------------------------------------------------------------+| STOP_SECONDARY_ENGINE_INCREMENT_LOAD_TASK('aptest', 'user') |+-----------------------------------------------------------------+| success                                                         |+-----------------------------------------------------------------+1 row in set (0.21 sec)
greatsql> SELECT * FROM information_schema.SECONDARY_ENGINE_INCREMENT_LOAD_TASK\G*************************** 1. row *************************** DB_NAME: aptest TABLE_NAME: user START_TIME: 2024-02-21 09:33:55 START_GTID: 9548406d-8ff1-11ee-97ec-ec5c6826bca3:1-3808COMMITTED_GTID_SET: 9548406d-8ff1-11ee-97ec-ec5c6826bca3:1-3821 READ_GTID: 9548406d-8ff1-11ee-97ec-ec5c6826bca3:3821 READ_BINLOG_FILE: ./binlog.000023 READ_BINLOG_POS: 596312770 DELAY: 60 STATUS: NOT RUNNING END_TIME: 2024-02-21 09:35:46 INFO: NORMAL EXIT1 row in set (0.00 sec)
复制代码


更多 Rapid 存储引擎介绍请前往 GreatSQL 用户手册上查看 Rapid 引擎(Rapid Engine)https://greatsql.cn/docs/8032-25/user-manual/5-enhance/5-1-highperf-rapid-engine.html

总结

对于在不改造 SQL 的前提下,查询速度提升了 26.9 倍 的这一结果,潲同学表示非常惊讶。然而,令人遗憾的是,他们尚未迁移到 GreatSQL 数据库。因此,他目前正紧锣密鼓地向总监提议,争取尽快完成迁移并采用 GreatSQL 数据库:)


目前 Rapid 存储引擎已经开放测试了,欢迎各位来体验测试~


GreatSQL 手册:https://greatsql.cn/docs/8032-25/


GreatSQL 下载地址:https://gitee.com/GreatSQL/GreatSQL/releases/tag/GreatSQL-8.0.32-25

发布于: 刚刚阅读数: 5
用户头像

GreatSQL

关注

GreatSQL社区 2023-01-31 加入

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。 社区:https://greatsql.cn/ Gitee: https://gitee.com/GreatSQL/GreatSQL

评论

发布
暂无评论
AP引擎助力加速生产SQL运行_数据库_GreatSQL_InfoQ写作社区