最大兼容模式 #
在真实业务系统中,单表操作占据了大量请求。对于这类 SQL,如果已经能够确定访问的数据源,并且不需要改写执行,SphereEx-DBPlusEngine 可以在识别 SQL 关键信息后直接透传执行,减少完整解析、绑定、改写和结果归并带来的额外开销,从而提升性能。
最大兼容模式(Max Compatibility)首先用于提升单表操作的执行性能,其次用于提升 SQL 兼容性。对于包含数据库方言函数、特殊语法、复杂查询结构或历史兼容写法的 SQL,只要底层数据库能够正确执行,且当前规则允许,SphereEx-DBPlusEngine 会尽量保留原始 SQL 下发。
概述 #
最大兼容模式主要解决两类问题:
- 提升单表操作性能。
对于不需要复杂规则改写的单表 SQL,SphereEx-DBPlusEngine 在识别 SQL 类型、表名、参数等关键信息后,可以尽量透传到底层数据库执行,减少普通路径中的完整解析、绑定、SQL 改写和结果处理成本。
- 提升 SQL 兼容性。
对于底层数据库支持、但 SphereEx-DBPlusEngine 不需要完整理解的方言语法、函数或复杂表达式,可以在规则允许时尽量由底层数据库直接处理,降低业务 SQL 改造成本。
最大兼容模式不是一项独立的数据治理规则,它会和单表、读写分离、数据库发现、数据加密、数据脱敏、数据防篡改、异构双写等规则共同工作。SQL 是否能够使用最大兼容模式,取决于 SQL 本身以及当前启用规则是否允许。
基本概念 #
逻辑 SQL #
逻辑 SQL 是业务应用发送给 SphereEx-DBPlusEngine 的 SQL。
对于符合条件的单表 SQL,原始逻辑 SQL 可以尽量透传到底层数据库执行。
轻量识别 #
最大兼容模式不会完整理解 SQL 的所有语法细节,而是优先识别执行所需的关键信息,例如:
- SQL 类型,例如
SELECT、INSERT、UPDATE、DELETE; - SQL 涉及的业务表;
- 参数占位符数量;
- 是否包含加锁查询;
- 是否包含
LAST_INSERT_ID; - 是否包含
sequence.nextval。
这些信息用于快速判断 SQL 是否满足最大兼容模式的执行条件:例如是否属于可处理的 SQL 类型、是否能够定位到目标表和数据源、参数数量是否匹配、是否存在加锁查询、序列等会影响路由或规则判断的特征。只有当 SQL 本身和当前启用的规则都允许时,SphereEx-DBPlusEngine 才会尽量跳过普通路径中的完整解析、绑定和改写,将原始 SQL 下发到底层数据库执行。
内核执行 #
如果 SQL 或规则不适合最大兼容模式,SphereEx-DBPlusEngine 会回到内核执行流程,继续完成 SQL 解析、绑定、路由、改写和结果处理。
单表元数据懒加载 #
单表元数据懒加载是指:没有在启动阶段预加载的单表,在运行时被 SQL 访问并确实需要表结构时,再按需加载表元数据。
最大兼容模式本身不等于“永不加载元数据”。当 SQL 回退内核执行路径,或者 SQL 需要展开 *、表别名.* 时,仍可能读取表结构,加载表元数据。
适用场景 #
最大兼容模式适用于以下场景:
- 单表
SELECT、INSERT、UPDATE、DELETE操作,不需要加密、脱敏、防篡改等列级改写; - SQL 可以确定访问的数据源,适合尽量透传执行;
- SQL 能够被底层数据库直接执行;
- SQL 能够识别出业务表;
- 当前启用的规则都允许该 SQL 使用最大兼容模式;
- 读写分离、数据库发现等场景中,需要根据 SQL 类型和少量特征完成判断;
- SQL 中包含底层数据库支持的方言语法、函数或复杂表达式,希望尽量由底层数据库处理。
常见示例:
-- 假设 t_profile 是单表
SELECT id, user_id, note FROM t_profile WHERE user_id = ?
使用限制 #
以下场景通常不会使用最大兼容路径,或者会回退到普通内核执行路径:
- SQL 命中加密表,需要对逻辑列、密文列、明文列或辅助查询列进行改写;
- SQL 命中脱敏表,需要对返回结果进行脱敏处理;
- SQL 命中防篡改表,需要维护或校验摘要列;
- 异构双写中的
INSERT; - 异构双写中包含 SQL 翻译参数列;
- 异构双写中包含
sequence.nextval; - SQL 无法识别出明确的业务表;
- SQL 需要依赖完整语义处理才能保证规则正确生效。
使用最大兼容模式时,不应把它理解为绕过数据治理规则。只要 SQL 命中需要规则改写或规则保护的表,SphereEx-DBPlusEngine 仍会优先保证规则正确性。
原理介绍 #
最大兼容模式的核心原则是:在规则可判断、路由可确定、数据治理语义不受影响的前提下,优先让符合条件的单表 SQL 透传执行,并尽量将复杂 SQL 交给底层数据库处理。
执行流程 #
最大兼容模式处理 SQL 的过程如下:
- 应用发送 SQL 到 SphereEx-DBPlusEngine。
- SphereEx-DBPlusEngine 判断是否开启最大兼容模式。
- 识别 SQL 类型、表名、参数占位符和特殊执行特征。
- 检查当前启用的规则是否允许该 SQL 使用最大兼容模式。
- 如果允许,则尽量保留原始 SQL 完成路由和执行。
- 如果不允许,则回到普通内核 SQL 处理路径。
与各类规则的关系 #
不同规则对最大兼容模式的要求不同:
| 规则 | 行为说明 |
|---|---|
| 单表 | 一般允许使用最大兼容模式。符合条件时,可以尽量透传执行以减少普通路径开销。 |
| 读写分离 | 一般允许使用最大兼容模式,根据 SQL 类型、加锁查询等信息判断主库或从库。 |
| 数据库发现 | 一般允许使用最大兼容模式,由高可用规则决定可用数据源。 |
| 数据加密 | SQL 未命中加密表时可以使用;命中加密表时通常需要普通路径进行列改写。 |
| 数据脱敏 | SQL 未命中脱敏表时可以使用;命中脱敏表时通常需要普通路径进行结果处理。 |
| 数据防篡改 | SQL 未命中防篡改表时可以使用;命中防篡改表时通常需要普通路径维护摘要列。 |
| 异构双写 | 普通查询可以使用;INSERT、包含 SQL 翻译参数列或包含序列时不使用。 |
操作指南 #
开启最大兼容模式 #
在 YAML 配置中设置:
props:
max-compatibility-enabled: true
也可以通过 DistSQL 动态开启:
SET DIST VARIABLE max_compatibility_enabled = true;
开启后可以通过以下 DistSQL 查看配置:
SHOW DIST VARIABLE WHERE name = max_compatibility_enabled;
配置单表 #
如果希望启动时加载并管理全部单表,可以配置:
rules:
- !SINGLE
tables:
- "*.*"
| 配置方式 | 行为 |
| tables: "*.*" | 启动阶段扫描并加载全部单表。 |
如果期望启动阶段不加载所有单表元数据,仅在运行阶段需要时才加载,则不需要配置单表规则,或者单表规则里只配置您需要启动阶段加载的单表。
配置示例 #
单表查询 #
适用于单数据源或单表查询,希望减少普通解析和改写开销,并尽量保留原始 SQL 的场景。
databaseName: demo_db
dataSources:
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:3306/demo_ds?serverTimezone=UTC&useSSL=false
username: root
password: root
rules:
- !SINGLE
defaultDataSource: ds_0
props:
sql-show: true
max-compatibility-enabled: true
业务 SQL 示例:
SELECT id, user_id, note FROM t_profile WHERE user_id = ?
该 SQL 不包含 *,也没有命中需要列级改写的规则,适合通过最大兼容模式透传执行,以减少普通路径开销。
单表与加密表混合查询 #
以下示例中,t_profile 为单表,t_user 为加密规则表。
databaseName: demo_db
dataSources:
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:3306/demo_ds?serverTimezone=UTC&useSSL=false
username: root
password: root
rules:
- !SINGLE
defaultDataSource: ds_0
- !ENCRYPT
encryptors:
aes_encryptor:
type: AES
props:
aes-key-value: 123456abc
tables:
t_user:
columns:
user_name:
plain:
name: user_name
queryWithPlain: true
cipher:
name: user_name_cipher
encryptorName: aes_encryptor
props:
sql-show: true
max-compatibility-enabled: true
业务 SQL 示例:
SELECT p.*, u.user_name
FROM t_profile p
JOIN t_user u ON p.user_id = u.user_id
WHERE p.user_id = ?
该 SQL 命中加密表 t_user,通常需要普通路径处理加密列。如果同时包含 p.*,普通路径需要读取 t_profile 的列信息,因此可能触发单表元数据懒加载。
如果单纯的单表查询,不涉及加密表,即使当前配置包含加密规则,也可以走最大兼容模式。
异构双写查询 #
异构双写场景下,普通查询可以使用最大兼容模式。例如:
SELECT id, user_id, note FROM t_dw_seq_single WHERE id = ?
如果 SQL 包含序列,例如 Oracle 中常见的 sequence.nextval:
SELECT order_seq.nextval AS generated_id, p.* FROM t_dw_seq_single p WHERE p.id = ?
需要注意:
- 包含序列时,异构双写不会使用最大兼容路径;
- 上例中真正容易触发单表元数据加载的是
p.*,因为普通路径需要展开表的所有列; - 不能简单理解为“有序列就一定加载元数据”。
如果希望减少运行时元数据加载,建议显式写出业务列:
SELECT order_seq.nextval AS generated_id, p.id, p.user_id, p.note
FROM t_dw_seq_single p
WHERE p.id = ?
常见问题 #
开启最大兼容模式后,SQL 一定原样下发吗? #
不一定。只有 SQL 类型、涉及表和当前规则都满足条件时,才会尽量原样下发。
命中加密表、脱敏表、防篡改表,或异构双写中的 INSERT、序列等场景时,可能回到内核执行路径。
最大兼容模式会绕过加密、脱敏或防篡改规则吗? #
不会。最大兼容模式会先判断当前规则是否允许该 SQL 使用最大兼容路径。只要 SQL 需要规则改写或规则保护,就会回到普通内核执行路径处理。
如何减少运行时单表元数据加载? #
- 不配置
!SINGLE tables: "*.*",避免把启动预加载误判为运行时加载; - 在高频 SQL 中避免使用
*或表别名.*; - 对需要稳定低延迟的单表,使用
!SINGLE tables显式加载; - 通过
sql-show观察 actual SQL 是否出现列展开。