**openGauss xx特性设计说明书**
所属SIG组: Plugin
落入版本: 20220630
设计人员: 彭炯
日期: 2022/04/06
**Copyright © 2022 openGauss Community** 您对"本文档"的复制,使用,修改及分发受知识共享(Creative Commons)署名—相同方式共享4.0国际公共许可协议(以下简称"CC BY-SA 4.0")的约束。 为了方便用户理解,您可以通过访问了解CC BY-SA 4.0的概要 (但不是替代)。 CC BY-SA 4.0的完整协议内容您可以访问如下网址获取:。 **改版记录**
日期 修订版本 修订描述 作者 审核
2022/04/03 0.0.1 初稿 彭炯
2022/04/07 1.0.0 去掉openGauss取值范围比MySQL大的兼容项,不需要缩小范围 彭炯 xxx
**目录** 1.特性概述 1.1范围 1.2特性需求列表 2.需求场景分析 2.1特性需求来源与价值概述 2.2特性场景分析 2.3特性影响分析 2.3.1硬件限制 2.3.2技术限制 2.3.3对License的影响分析 2.3.4对系统性能规格的影响分析 2.3.5对系统可靠性规格的影响分析 2.3.6对系统兼容性的影响分析 2.3.7与其他重大特性的交互性,冲突性的影响分析 2.4同类社区/商用软件实现方案分析 3.特性/功能实现原理(可分解出来多个Use Case) 3.1目标 3.2总体方案 4.Use Case一实现 4.1设计思路 4.2约束条件 4.3详细实现(从用户入口的模块级别或进程级别消息序列图) 4.4子系统间接口(主要覆盖模块接口定义) 4.5子系统详细设计 4.6DFX属性设计 4.6.1性能设计 4.6.2升级与扩容设计 4.6.3异常处理设计 4.6.4资源管理相关设计 4.6.5小型化设计 4.6.6可测性设计 4.6.7安全设计 4.7系统外部接口 4.8自测用例设计 5.Use Case二实现 6.可靠性&可用性设计 6.1冗余设计 6.2故障管理 6.3过载控制设计 6.4升级不中断业务 6.5人因差错设计 6.6故障预测预防设计 7.安全&隐私&韧性设计 7.1Low Level威胁分析及设计 7.1.12层数据流图 7.1.2业务场景及信任边界说明 7.1.3外部交互方分析 7.1.4数据流分析 7.1.5处理过程分析 7.1.6数据存储分析 7.1.7缺陷列表 7.2隐私风险分析与设计 7.2.1隐私风险预分析问卷 7.2.2隐私风险预分析总结 7.2.3个人数据列表 7.2.4XX需求设计 7.2.5YY需求设计 8.特性非功能性质量属性相关设计 8.1可测试性 8.2可服务性 8.3可演进性 8.4开放性 8.5兼容性 8.6可伸缩性/可扩展性 8.7 可维护性 8.8 资料 9.数据结构设计(可选) 10.参考资料清单 **表目录** 表X:特性场景相关性分析 表X:特性需求列表 **图目录** 图X:方案总体实现原理图 图X:样图:处理流程示意图 **List of abbreviations** **缩略语清单** :
Abbreviations 缩略语 Full spelling 英文全名 Chinese explanation 中文解释
xxx xxx xxx
xxx xxx xxx
# 1.特性概述 本特性设计兼容MySQL的多个数据类型,使得客户将MySQL数据库迁移至openGauss时,能更少的修改应用。本特性的所有修改均基于b_sql_plugin插件实现。 ## 1.1范围 兼容bit/tinyint/smallint/mediumint/int/bigint/char/varchar/nvarchar/text共10个数据类型。 ## 1.2特性需求列表 表X:特性需求列表
需求编号 需求名称 特性描述 备注
1 兼容bit(n)数据类型 对于bit(n)类型,支持插入比n长度短的二进制字符串 openGauss当前必须插入n为二进制字符串,否则校验不通过报错
2 兼容tinyint(n)数据类型 兼容tinyint(n)类型,n无实际作用,忽略即可 当前openGauss的tinyint默认为无符号,而MySQL的tinyint默认为有符号,本次特性不对此进行修改
3 兼容smallint(n)数据类型 兼容smallint(n)类型,n无实际作用,忽略即可
4 兼容mediumint/mediumint(n)数据类型 内部使用int4实现,同时n无实际作用,忽略即可 MySQL的mediumint占3个字节,取值范围为-8388608~8388607,目前openGauss没有此种大小的整形,使用int4替代,实际取值范围比MySQL的更大
5 兼容int(n)数据类型 兼容int(n)类型,n无实际作用,忽略即可
6 兼容bigint(n)数据类型 兼容bigint(n)类型,n无实际作用,忽略即可
7 兼容char/varchar/nvarchar/text字符数据类型 对于字符串尾部的空格,存储时不截断,比较时会截断。即'a'='a '为真 openGauss中,对于字符串尾部的空格,存储时不截断,比较时也不截断
# 2.需求场景分析 ## 2.1特性需求来源与价值概述 本特性需求只要兼容常用的MySQL数据类型,使得客户将MySQL数据库迁移至openGauss时,能更少的修改应用,更符合以前的使用习惯,降低客户从MySQL迁移到openGauss的成本。 ## 2.2特性场景分析 用户在通过gsql等openGauss客户端/驱动连接openGauss后,在建表等语句中,可以使用本特性兼容的数据类型,且表现和MySQL 5.7基本一致。 ## 2.3特性影响分析 ### 2.3.1硬件限制 无 ### 2.3.2 技术限制 本特性基于b_sql_plugin插件开发,如需使用相关特性,需要加载b_sql_plugin插件。 ### 2.3.3 对License的影响分析 本特性的代码基于openGauss b_sql_plugin插件开发,特性代码没有参考MySQL,没有引入新的三方件,对License无影响。 ### 2.3.4对系统性能规格的影响分析 1. 对于tinyint、smallint、mediumint、int、bigint等数据类型,只涉及建表语句时的兼容,对性能无影响。 2. 对于bit、字符数据类型,涉及建表、插入时的合法性校验、where/join过滤条件对比,预计在建表、插入时的合法性校验这两个场景性能无劣化。在where/join过滤条件对比字符数据类型时,由于需要先截断尾部的空格再对比,预计在部分场景下性能会差于原始场景。 ### 2.3.5对系统可靠性规格的影响分析 不涉及 ### 2.3.6对系统兼容性的影响分析 前向兼容分析: 1. bit(n),修改前,插入的数据长度必须为n,修改后,插入数据的长度可小于n。 2. tinyint(n)。无影响。 3. smallint(n)。无影响。 4. mediumint。原来mediumint不是关键字,改为数据类型后,mediumint将作为col_name_keyword(非保留关键字,但是不能是函数或类型) 5. int(n)。无影响。 6. bigint(n)。无影响。 8. char/varchar/nvarchar/text字符类型。主要影响join/where条件下过滤出来的数据,原来'a' = 'a '为false,兼容性后为true。 ### 2.3.7与其他重大特性的交互性,冲突性的影响分析 无 ## 2.4 同类社区/商用软件实现方案分析 无 # 3.特性/功能实现原理(可分解出来多个Use Case) ## 3.1目标 本特性的数据类型在建表、插入数据、join/where场景下,基本表现同MySQL 5.7. ## 3.2总体方案 对于tinyint(n)、smallint(n)、int(n)、bigint(n),仅需兼容(n),修改gram.y即可,在语法层兼容(n),但是对实际内容进行忽略,使xx(n)等价于xx。 对于mediumnint,新增mediumnint作为col_name_keyword类型关键字,并将其转换成int4数据类型。 对于字符数据类型的尾部空格字符截断问题,需要修改 <=、>=、=操作符涉及的内部函数,在对字符串进行比较前,去除尾部空格。 # 4.Use Case一实现 ## 4.1设计思路 对于tinyint(n)、smallint(n)、int(n)、bigint(n),在gram.y中直接增加可选的opt_type_modifiers即可: ``` | SMALLINT opt_type_modifiers { $$ = SystemTypeName("int2"); $$->location = @1; } ``` 对于mediumnint,新增mediumnint作为col_name_keyword类型关键字,并将mediumint放到Numeric类型下,和其他数字类型放到一起。 ``` PG_KEYWORD("mediumint", MEDIUMINT, COL_NAME_KEYWORD) ``` ``` | MEDIUMINT opt_type_modifiers { $$ = SystemTypeName("int4"); $$->location = @1; } ``` 对于字符数据类型的尾部空格字符截断问题。目前openGauss对比两个字符数据类型是否相同是通过先判断两个字符串长度是否相等,然后再通过 memcmp 比较内容是否相同。根据这个原则,如果想在对比时截断尾部空格,只需要在计算字符串长度时,不将尾部的空格算入即可。 原算法: ```C len1 = toast_raw_datum_size(arg1); len2 = toast_raw_datum_size(arg2); if (len1 != len2) { result = false; } else { text* targ1 = DatumGetTextPP(arg1); text* targ2 = DatumGetTextPP(arg2); result = (memcmp(VARDATA_ANY(targ1), VARDATA_ANY(targ2), len1 - VARHDRSZ) == 0); } ``` 新算法: ```C len1 = toast_raw_datum_size(arg1) - VARHDRSZ; len2 = toast_raw_datum_size(arg2) - VARHDRSZ; if (DB_IS_CMPT(B_FORMAT)) { targ1 = DatumGetTextPP(arg1); targ2 = DatumGetTextPP(arg2); parg1 = VARDATA_ANY(targ1); parg2 = VARDATA_ANY(targ2); len1 = StrLenWithoutTailBlank(parg1, len1); len2 = StrLenWithoutTailBlank(parg2, len2); } if (len1 != len2) { result = false; } else { if (targ1 == NULL) { targ1 = DatumGetTextPP(arg1); parg1 = VARDATA_ANY(targ1); } if (targ2 == NULL) { targ2 = DatumGetTextPP(arg2); parg2 = VARDATA_ANY(targ2); } result = (memcmp(parg1, parg2, len1) == 0); } /* Calculate the length without tail blank */ static inline Size StrLenWithoutTailBlank(char *str, Size realLen) { Size len = realLen; str = str + realLen - 1; while (realLen > 0 && *str == ' ') { len--; str--; } return len; } ``` 需要注意是,相比于原来的text_cmp,对于性能最主要的影响是对比时需要先将text detoast。因为字符串的长度是可以通过toast_raw_datum_size方法直接获得,不需要将内容先detoast,只有当两个text长度相同时,才会将内容detoast并通过memcmp进行对比。 而兼容方案中,为了能在对比时忽略尾部空格,只能先将text detoast,并遍历尾部的内容以确定不含尾部空格时的字符长度,预计对于本身长度就不相等的字符串场景下,对比耗时将增加,因为多了detoast的耗时。 另外此修改同时影响其他使用text_cmp做对比的数据类型,包括char/varchar/varchar2/nvarchar2/text/clob。MySQL的尾部空格截断也同样适用于其他字符数据类型,包括char/varchar/nvarchar/text。可使用如下SQL在MySQL上测试: ```SQL create table t_ch(a char(10), b varchar(10), c nvarchar(10), d text); insert into t_ch values('a ','a ','a ','a '); insert into t_ch values('a','a','a','a'); select * from t_ch where a='a '; select * from t_ch where a='a '; select * from t_ch where a='a'; ``` 性能测试对比: ```SQL ---建表 create table t1(a text); ---插入数据,55条,每条长200MB insert into t1 values (lpad('a',209715200,'c')); ---执行查询 select * from t1 where a='a '; ``` 对于原始openGauss,对比是否相等时先判断长度,无需将数据detoast,所以对于这种场景,查询速度很快: ```SQL openGauss=# select length(a) from t1 limit 1; length ----------- 209715200 (1 row) Time: 1889.678 ms openGauss=# select count(*) from t1; count ------- 55 (1 row) Time: 0.479 ms openGauss=# select * from t1 where a='a '; a --- (0 rows) Time: 0.361 ms ``` 修改后,由于需要对每条数据都先detoast,查询速度明显降低: ```SQL b_test=# select length(a) from t1 limit 1; length ----------- 209715200 (1 row) Time: 2459.771 ms b_test=# select count(*) from t1; count ------- 55 (1 row) Time: 0.562 ms b_test=# select * from t1 where a='a '; a --- (0 rows) Time: 29416.276 ms ``` MySQL的情况: ```SQL MySQL [pengjiong]> select length(a) from t1 limit 1; +-----------+ | length(a) | +-----------+ | 209715200 | +-----------+ 1 row in set (0.17 sec) MySQL [pengjiong]> select count(*) from t1; +----------+ | count(*) | +----------+ | 55 | +----------+ 1 row in set (0.00 sec) MySQL [pengjiong]> select * from t1 where a='a '; Empty set (11.32 sec) ``` MySQL的查询情况比openGauss快,猜测应该是由于openGauss是将大的text压缩后存到toast中,而MySQL好像没有类似功能,所以对比时,openGauss多了一个detoast的消耗。 由于此种做法对于长字符串(特别是触发了toast存储的字符串)的比较会带来较大的性能损耗,需要判断是否有必要做这个兼容。 由于本身openGauss自带的压缩+toast功能,导致从toast获取数据+解压的操作比MySQL更耗时,所以在上述有toast+压缩的场景下,性能损耗很大。尝试测试下没有压缩+toast的场景,性能是否有劣化。 通过测试,发现当text的长度 > 2004 时,会触发压缩,如果压缩后的长度仍超过 2004,触发toast。(相关代码: heap_prepare_insert -> toast_insert_or_update) 测试在不需要压缩&toast的场景下,测试性能。用例如下: ```SQL ---建表 create table t1(a text); ---插入数据,插入102400条相同的数据 insert into t1 values (lpad('a',2004,'c')); ---查看表大小 ---openGauss b_test=# select pg_size_pretty(pg_table_size('t1')); pg_size_pretty ---------------- 200 MB (1 row) ---MySQL mysql> select concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data from TABLES where table_name='t1'; +----------+ | data | +----------+ | 229.78MB | +----------+ 1 row in set (0.02 sec) ``` 使用 ```select * from t1 where a='a '; ``` 连续测试查询性能,耗时如下:
MySQL openGauss(修改前) openGauss(修改后)
第一次 0.24 sec 190.969 ms 186.728 ms
第二次 0.24 sec 185.994 ms 185.775 ms
第三次 0.27 sec 186.181 ms 185.302 ms
第四次 0.25 sec 189.880 ms 187.398 ms
第五次 0.27 sec 188.869 ms 187.798 ms
平均值 0.254 sec 0.188 sec 0.187 sec
另有一个设计问题,由于所有修改均基于b_sql_plugin插件修改,修改的代码是否还有必要继续使用DB_IS_CMPT(B_FORMAT)来进行控制?因为b_sql_plugin已经限制了只有B数据库才能加载。看起来这个判断是多余的。 总的来看,如果不使用DB_IS_CMPT(B_FORMAT)控制,直接修改原有逻辑,好处是代码更好看,不会有较多的 if 判断分支,逻辑更清晰。如果使用DB_IS_CMPT(B_FORMAT)控制,好处是保留了原始的openGauss处理逻辑,后续如果openGauss内核对相关代码有修改,能较为方便的同步到b_sql_plugin插件,也能比较清晰的看出B兼容模式下和原来逻辑的区别。 SIG例会评审确认:无需使用DB_IS_CMPT(B_FORMAT)控制,直接修改原有逻辑即可。 ## 4.2约束条件 基于b_sql_plugin插件实现,需加载b_sql_plugin插件才能使用。相关约束继承b_sql_plugin原有约束,如不能在非B类型数据库上使用等。 ## 4.3详细实现(从用户入口的模块级别或进程级别消息序列图) 见4.1设计思路。 ## 4.4子系统间接口(主要覆盖模块接口定义) 不涉及子系统间接口修改。 ## 4.5子系统详细设计 见4.1设计思路。 ## 4.6DFX属性设计 ### 4.6.1性能设计 特性会影响已有的char/varchar/varchar2/nvarchar2/text/clob数据类型的比较性能,主要是在join和where场景下,对于长字符串类型的等值比较(含 =、>=、<=)有影响。其他场景只涉及语法解析层的小改动、以及对typmod的校验,对性能无影响。 ### 4.6.2升级与扩容设计 随插件一起升级/扩容。不单独设计升级方案。 ### 4.6.3异常处理设计 不涉及 ### 4.6.4资源管理相关设计 不涉及 ### 4.6.5小型化设计 不涉及 ### 4.6.6可测性设计 测试应该涵盖的内容: 1. 建表时支持tinyint(n)/smallint(n)/int(n)/bigint(n)的语法,且不校验n的数值 2. 对于bit(n),插入数据时,分别插入比n大、等于n、小于n的数据量 3. 建表时使用mediumint/mediumint(n),且不校验n的数值,内部使用int4存储 7. 对于char/varchar/varchar2/nvarchar2/text/clob等字符数据类型,在join、where等场景下,测试尾部空格是不会影响过滤结果。 ### 4.6.7安全设计 不涉及 ## 4.7系统外部接口 影响SQL语法,特别的,影响建表语句中,对本特性兼容的数据类型的使用方法。 ## 4.8自测用例设计 自测用例基于 4.6.6可测性设计章节编写。主要覆盖边界值等场景。 # 6.可靠性&可用性设计 ## 6.1冗余设计 不涉及 ## 6.2故障管理 不涉及 ## 6.3过载控制设计 不涉及 ## 6.4升级不中断业务 升级问题依赖插件,本特性不涉及升级相关设计。 ## 6.5人因差错设计 不涉及 ## 6.6故障预测预防设计 不涉及 # 7.安全&隐私&韧性设计 ## 7.1Low Level威胁分析及设计 ### 7.1.12层数据流图 仅增加语法兼容和数据类型的内部表现差异,不涉及修改/新增外部实体交互。 ### 7.1.2业务场景及信任边界说明 不涉及 ### 7.1.3外部交互方分析 不涉及 ### 7.1.4数据流分析 不涉及 ### 7.1.5处理过程分析 不涉及 ### 7.1.6数据存储分析 不涉及 ### 7.1.7缺陷列表 不涉及 ## 7.2隐私风险分析与设计 ### 7.2.1隐私风险预分析问卷
序号 问题 是否满足 填写指导
1 该产品是否收集或处理个人数据
2 上一版本是否做过隐私风险分析
3 当前版本是否有新增特性收集或处理个人数据
4 当前版本是否存在个人数据收集范围发生变化
5 当前版本是否存在个人数据收集范围发生变化
### 7.2.2隐私风险预分析总结 当前版本不涉及个人数据收集,因此该版本无需做隐私风险分析。 ### 7.2.3个人数据列表 不涉及 ### 7.2.4XX需求设计 7.2.4.1需求说明 不涉及 7.2.4.2需求设计 不涉及 ### 7.2.5YY需求设计 # 8.特性非功能性质量属性相关设计 ## 8.1可测试性 参考4.6.6可测性设计 ## 8.2可服务性 目前b_sql_plugin插件不是默认加载,相关兼容点目前单独将资料添加到 https://gitee.com/opengauss/Plugin/tree/master/contrib/b_sql_plugin/doc 目录下,里面的内容和doc仓库保持一致,后续视实际情况将资料同步到doc仓。 ## 8.3可演进性 基于b_sql_plugin插件,可演进性依赖b_sql_plugin插件。 ## 8.4开放性 没有新增对外接口。 ## 8.5兼容性 前向兼容性说明,见2.3.6对系统兼容性的影响分析 ## 8.6可伸缩性/可扩展性 不涉及。可伸缩性/可扩展性依赖b_sql_plugin插件。 ## 8.7可维护性 对于输入异常的场景,有错误信息打印。无须增加诊断视图。 ## 8.8资料
类别 手册名称 是否涉及(Y/N) 具体修改或新增内容简述
白皮书 技术白皮书 N 不涉及
产品文档 产品描述 N 不涉及
特性描述 N 不涉及
编译指导书 N 不涉及
安装指南 N 不涉及
管理员指南 N 不涉及
开发者指南 (包括开发教程、SQL参考、系统表和系统视图、GUC参数说明、错误码说明、API参考等) Y 在关键字章节增加mediumnint作为非保留(不能是函数或类型)关键字;修改数值类型中,对于(n)的兼容描述,增加mediumnint的描述;修改位串类型中,对于bit(n)中n的描述。以上文档修改将合入Plugin仓库,暂不合入doc仓库
工具参考 N 不涉及
术语表 N 不涉及
入门 简易教程 N 不涉及
# 9.数据结构设计(可选) 不涉及 # 10.参考资料清单 bit: https://dev.mysql.com/doc/refman/5.7/en/bit-type.html tinyint/smallint/mediumint/int/bigint: https://dev.mysql.com/doc/refman/5.7/en/integer-types.html char/varchar: https://dev.mysql.com/doc/refman/5.7/en/char.html