0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

异构数据库排序一致性填坑教程

jf_78858299 来源:基础技术研究 作者:陈伟 2023-03-29 13:43 次阅读

不同数据库对于字符值的排序规则各不相同,要达成在不同数据库上对于同样数据集执行查询语句的输出结果顺序一致性目标,则必须进行相应的设置或改写,本文通过对五种数据库的分析,对该问题进行了较为深入的分析。

01

概述.

在异构数据库之间进行数据迁移之后,为验证数据一致性,就需要比对源库和目标库的同表数据是否一致。

为了提高比对效率,一般而言会将数据排序并抽取出来后进行比对。

在实际过程中发现,指定了ORDER BY的同样两条SQL语句在不同数据库执行后,输出结果集的顺序经常会不同,本文关注该问题的产生并提供了相应的解决方案。

02

数据准备.

本文涉及的数据库为:

  • Oracle
  • MySQL
  • Postgres
  • Gauss(华为open Gauss)
  • GoldiLocks(科蓝)

所有的数据库均采用UTF8编码,且MySQL数据库不区分大小写建表。

在各数据库中创建一张测试表LEXSORT,该表仅有一个字符列NAME,具体语句如下:

CREATE TABLE LEXSORT ( NAME VARCHAR(10) );

然后将以下数据插入该表中:

INSERT INTO LEXSORT VALUES ('0');
INSERT INTO LEXSORT VALUES ('9');
INSERT INTO LEXSORT VALUES ('a');
INSERT INTO LEXSORT VALUES ('z');
INSERT INTO LEXSORT VALUES ('A');
INSERT INTO LEXSORT VALUES ('Z');
INSERT INTO LEXSORT VALUES ('_');
INSERT INTO LEXSORT VALUES ('~');
INSERT INTO LEXSORT VALUES (NULL);

03

查询结果.

在各个数据库中执行如下查询语句:

SELECT * FROM LEXSORT ORDER BY NAME;

其输出结果见下图:

图片

通过上面的结果可以发现:

其一,Oracle、Gauss和GoldiLocks的缺省排序保持一致,而与MYSQL和Postgres的各不相同。

其二,数据排序的不同体现在两个方面上

  • NULL值与非NULL字符值之间的顺序
  • 非NULL字符值之间的顺序

那么,这背后的机制是什么呢?又该如何解决呢?

04

数据库分析.

其实,产生这一现象的原因是各数据库的缺省排序规则各不相同所致。要解决这一问题,就需要从各数据库自身出发,了解其排序规则,并分别进行设置,才可能达到在不同数据库之间的一致性。

具体如何操作,后文将为您逐一展开。

Oracle数据库

**Oracle数据库提供了控制排序规则的参数,可以在系统级别和会话级别分别进行设置,一般而言,为了不影响其他应用,我们在会话级别进行设置即可。

**

1. NULL值的排序规则

Oracle支持在ORDER BY字句的每个字段上进行控制。可以指定为NULLS FIRST或NULLS LAST,即NULL值排在前面还是后面,缺省为NULLS LAST,即NULL值排在其它非NULL值的后面。

Postgres、Gauss和GoldiLocks也采用了同样的处理,后文不再赘述。

2. 非NULL值的排序规则

Oracle提供了控制参数NLS_SORT来指定排序规则,缺省的排序规则为BINARY,即按照字符串中每个字符的编码值进行排序,另一个常用排序规则为BINARY_CI,即按照二进制值进行排序,同时字母(A-Z,a-z)不区分大小写。

根据以上规则重新修改一下SQL语句或会话设置:

ALTER SESSION SET NLS_SORT=BINARY;
ALTER SESSION SET NLS_SORT=BINARY_CI;
SELECT * FROM LEXSORT ORDER BY NAME NULLS FIRST;

此时不同组合后查询的输出结果见下图:

图片

在上图中我们会注意到,不区分大小写排序时字符“_”的位置似乎有些“飘忽不定”。为了解决这个问题,我们把这些字符对应的编码数值出来看一下:

图片

根据编码值就会发现,“飘忽不定”的符号“_”的编码正好位于大写字母和小写字母之间,与它存在同样情况的还有5个字符。这就意味着,Oracle在采用BINARY_CI方式忽略字母大小写排序时,会自动将所有的字母视为了小写字母。

MySQL数据库

MySQL数据库在排序控制方面较弱,首先对于NULL值,MySQL自动视为NULLS FIRST,在ORDER BY字句中无相应的控制选项。

再看一下字母的排序,MySQL在建表时可以指定区分大小写或不区分大小写,一旦指定无法再修改,除非重新建表。

因此对于区分大小写的库,其排序规则会与Oracle的BINARY规则保持一致。

那么不区分大小写的呢?其实在前面的截图中已经有了体现,不过为了清晰起见,我们将Oracle设置为NULL FIRST和不区分大小写,单独拿出来再进行一下比较:

图片

此时我们会发现Oracle和MySQL的排序依然不一致!发生问题的依然是那个“飘忽不定”的“_”。

显然,稍加分析后我们就会知道,在不区分大小写的情形下,MySQL自动将所有字母视为了大写字母进行排序,正是因为这个区别,位于大写和小写字母之间的那六个字符又一次给我们惹了麻烦。

这样,不区分大小写建表的MySQL数据库与Oracle数据库的排序一致性就不存在完美的解决方案!

Postgres数据库

Postgres数据库的缺省排序对我来说一直是个迷……

图片

上图中,符号排在最前面,而“~”的编码却比“_”大,相当于降序;然后是数字和字母,而此时又是升序。鉴于本人对Postgres的研究有限,此处暂不作深究,只专注如何解决排序一致性问题。

Postgres提供了collate语句用以调整排序规则。将排序规则设置为C(必须用双引号括起来且为大写字母)或ucs_basic(如果用双引号括起则必须为小写)则代表按照字符编码排序,此时会区分大小写。

不区分大小写且又要按照编码值进行排序,目前暂未找到合适的方法。

需要注意指定collate和null first时的SQL语句顺序问题,当二者都需指定时示例语句如下,具体的输出结果大家可以自行测试:

SELECT * FROM LEXSORT ORDER BY NAME COLLATE ucs_basic NULLS FIRST;

Gauss数据库

大家都知道Open Gauss实际上是基于Postgres进行的定制,它在增加部分功能的同时也删减了部分Postgres的功能。不过对于ORDER BY子句,Gauss依然保留了Postgres的能力,也就是说collate子句同样适用于Gauss数据库,不过Gauss数据库的缺省排序规则即为按照字符编码值进行排序。

同时,Gauss数据库提供了排序函数NLSSORT,解决了不区分大小排序的问题,此时其排序结果与Oracle保持一致。使用该函数时需指定排序规则,不区分大小写的规则为generic_m_ci,具体SQL示例语句如下:

SELECT * FROM LEXSORT ORDER BY NLSSORT(NAME,'nls_sort=generic_m_ci');
SELECT * FROM LEXSORT ORDER BY NLSSORT(NAME,'nls_sort=generic_m_ci') NULLS FIRST;

几种不同组合的查询结果见下图(未写明null first时均为nulls last):

图片

****GoldiLocks数据库 ****

该数据库除了NULLS FIRST/LAST处理与Oracle保持一致外,并没有可以修改排序规则的参数,不过其缺省的排序规则即为按照字符编码值进行排序。因此在排序一致性方面依然可以与Oracle、Postgres、Gauss做到很好的兼容。

05

总结.

虽然本文起源于数据比对场景,不过通过上面的分析,我们可以意识到,排序一致性问题也是异构数据库迁移时必须考虑的问题之一。试想一下,如果不做SQL语句改造,原有的业务查询语句在新数据库中结果集排序可能会发生变化,进而导致后续处理结果也可能发生变化。

通过分析我们也发现,大多数数据库的排序一致性可以通过设置会话参数或修改SQL语句等来实现保持不变,不过部分数据库,例如本例中的MySQL,却缺乏完美的解决方案,那么我们就必须要分析其影响并进行应对。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据库
    +关注

    关注

    7

    文章

    3591

    浏览量

    63379
  • Oracle
    +关注

    关注

    2

    文章

    277

    浏览量

    34927
  • 数据集
    +关注

    关注

    4

    文章

    1179

    浏览量

    24356
收藏 人收藏

    评论

    相关推荐

    相位一致性边缘检测

    大家起探讨相位一致性边缘检测,求指导
    发表于 06-11 13:38

    一致性测试

    谁有聚星公司射频一致性测试的程序啊,求个做参考,!
    发表于 07-14 18:11

    c6678cache一致性

    专家您好!    我现在在做6678 cache一致性的东西,想请问一下一致性的维护哪些是硬件实现的,哪些需要程序员实现?谢谢!
    发表于 06-24 04:38

    CAN一致性测试—容错测试

    ,就可以进行键自动化测试,完整显示测试结果、数据、波形截图等数据内容,工程师可快速判断被测设备的CAN总线质量。 CANDT一致性测试系统基于CANScope底层分析能力,集成示波
    发表于 11-22 16:36

    LTE基站一致性测试的类别

    就LTE基站而言,RF测试方法与一致性要求至为关键,然而,调变格式、带宽、资源分配与移动导致选项复杂度增加,因此优化的一致性测试配置参数组合需求更为殷切。第三代合作伙伴项目(3GPP)长期演进计划
    发表于 06-06 06:41

    MIPI一致性测试

    MIPI一致性测试测试项目:> TX测试;> RX测试;> S参数和阻抗测试;> DigRF,Unipro和LLI的测试;测试环境: MIPI测试对示波器带宽的要求 >
    发表于 09-26 13:31

    Infiniium一致性测试软件

    Infiniium 一致性测试软件
    发表于 10-28 17:28

    理解数据库的事务:ACID,CAP和一致性

    理解数据库的事务,ACID,CAP和一致性
    发表于 05-04 16:25

    什么是霍尔元件的一致性

    什么是霍尔元件的一致性?霍尔开关元件主要是通过感应磁性来进行开关机,霍尔元件本身又属于无触点开关,因此具有感应距离。霍尔开关都有个触发值和释放值,触发值是指霍尔元件表面达到参数磁性大小,霍尔元器件
    发表于 10-12 09:34

    如何确保蓝牙设计通过EMI一致性测试 ?

    选择蓝牙模块时需要考虑哪些因素?如何确保蓝牙设计通过EMI一致性测试 ?
    发表于 05-07 06:25

    如何实现信号电压幅值的一致性

    如何实现信号电压幅值的一致性
    发表于 05-20 07:23

    顺序一致性和TSO一致性分别是什么?SC和TSO到底哪个好?

    内存一致性之顺序一致性(sequential consistency)可以说,最直观的内存一致性模型是sequentially consistent(SC):内存访问执行的顺序与程序指定的顺序相同
    发表于 07-19 14:54

    在AXI中同时读写相同的address数据一致性怎么比较

    Arm AMBA协议集AXI中,同时读写相同的address,数据一致性怎么比较?
    发表于 09-15 15:03

    请问ESP-NOW对数据的完整一致性有校验吗?

    当使用ESP-NOW时,传递的数据在传输层有对数据包的完整(比如对面传给我的字节数和我收到的字节数是否相同)有底层校验吗?还有这个数据包是否经过了CRC等差错检测的校验呢(就是
    发表于 02-14 06:24

    虹科干货 | 什么是数据库一致性

    数据库一致性(database consistency)由一组值定义,数据库系统中的所有数据点都必须与这些值保持一致,才能正确读取和接受
    的头像 发表于 07-13 13:56 407次阅读
    虹科干货 | 什么是<b class='flag-5'>数据库</b><b class='flag-5'>一致性</b>?