Rapid存儲引擎簡介 從GreatSQL 8.0.32-25版本開始,新增Rapid存儲引擎,該引擎使得GreatSQL能滿足聯機分析(OLAP)查詢請求。 Rapid引擎採用插件(Plugin)方式嵌入GreatSQL中,可以線上動態安裝或卸載。 Rapid引擎不會直接面對客戶端和應用程式,用戶 ...
Rapid存儲引擎簡介
從GreatSQL 8.0.32-25版本開始,新增Rapid存儲引擎,該引擎使得GreatSQL能滿足聯機分析(OLAP)查詢請求。
Rapid引擎採用插件(Plugin)方式嵌入GreatSQL中,可以線上動態安裝或卸載。
Rapid引擎不會直接面對客戶端和應用程式,用戶無需修改原有的數據訪問方式。它是一個無共用、記憶體化、混合列式存儲的查詢處理引擎,其設計目的是為了高性能的處理分析型查詢。
並且在TPC-H性能表現優異在32C64G測試機環境下,TPC-H 100G測試中22條SQL總耗時 僅需不到80秒
下麵是幾個不同TPC-H數據量級的壓縮率數據:
TPC-H倉庫大小 | InnoDB引擎數據文件大小 | Rapid引擎數據文件大小 | 壓縮率 |
---|---|---|---|
TPC-H 1GB | 2003026076 | 276574208 | 7.24 |
TPC-H 100GB | 184570593436 | 28728373248 | 6.42 |
TPC-H 500GB | 1167795142848 | 146723045376 | 7.96 |
經過GreatSQL社區的測試分析可以看出,相較於InnoDB存儲引擎,Rapid存儲引擎在存儲效率上獲得了極大提升。在存放相同的數據集時,Rapid的數據文件所需要的空間僅為InnoDB的6~7分之1,大約 降低了85% 左右。
真實生產案例測試
為了全面驗證AP引擎的性能提升,我們成功獲取了真實生產環境下的SQL語句、表結構以及經過脫敏處理的數據。在此,特別感謝潲同學和貴司的協助!
測試環境介紹
本次測試採用的環境是 Arch Linux x86_64,機器配置為12C15G
$ uname -a
Linux 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 -l
12
$ free -h
total
Mem: 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 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;
真實生產表結構
生產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引擎提升查詢測試。
載入數據
鑒於原始數據較為有限,為了更明顯地進行測試,我們為每張表生成了一些新數據,來看下各表數據和表空間大小是多少:
表名 | 數據量 | 表空間大小 |
---|---|---|
dept | 11000 | 10M |
user | 100000 | 31M |
dept_tax | 10000 | 88M |
charge | 1000000 | 184M |
company | 1000 | 160K |
dept_info | 10000 | 11M |
company_bank | 1000 | 176K |
未改造測試
待測試的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 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;
先不使用AP引擎測試查詢五次:
測試次數 | 耗時 |
---|---|
第一次 | 10 rows in set (12.64 sec) |
第二次 | 10 rows in set (12.77 sec) |
第三次 | 10 rows in set (12.60 sec) |
第四次 | 10 rows in set (12.61 sec) |
第五次 | 10 rows in set (12.59 sec) |
可以看到五次測試結果都是穩定在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: 0
greatsql> 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: company
Create 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=rapid
1 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查詢時指定HINT
SELECT /*+ 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_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;
同樣測試查詢五次:
測試次數 | 耗時 |
---|---|
第一次 | 10 rows in set (0.48 sec) |
第二次 | 10 rows in set (0.47 sec) |
第三次 | 10 rows in set (0.46 sec) |
第四次 | 10 rows in set (0.48 sec) |
第五次 | 10 rows in set (0.46 sec) |
可以看到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: ALL
possible_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數據。
增量導入數據的限制和需求
在手冊上有介紹到增量導入數據的限制和需求,如下:
- 需要設置表名大小寫不敏感,即設置
lower_case_table_names = 1
。 - 需要開啟GTID模式,即設置
gtid_mode = ON
和enforce_gtid_consistency = ON
。 - 需要採用row格式的binlog event,不支持statement格式,即設置
binlog_format = ROW
。增量任務運行過程中,檢測到statement的DML event,可能會報錯退出。 - 需要關閉GIPKs特性,即設置
sql_generate_invisible_primary_key = OFF
。用戶表不能有 invisible primary key,如果表包含隱式不可見的主鍵,在全量導入過程中會報錯;同時也不支持用戶表中存在任何不可見列(invisible column)。 - 需要先對錶執行過一次全量導入後,才能啟動增量導入任務,否則任務啟動會報錯。
- 不支持 PARTIAL_UPDATE_ROWS_EVENT 類型的binlog,即不要設置
binlog_row_value_options = PARTIAL_JSON
。 - 不支持
CREATE TABLE SELECT
語句,增量任務運行過程中,檢測到該語句產生的binlog event時可能會報錯退出。 - 不支持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-3808
COMMITTED_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-3808
COMMITTED_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 EXIT
1 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
Enjoy GreatSQL