注册
关于影响merge的入库性能的一些影响因素
专栏/滴水藏海/ 文章详情 /

关于影响merge的入库性能的一些影响因素

yuao 2023/03/10 3917 12 1
摘要 举例说明可能与merge性能有关的一下设置和参数

1.背景说明:
    在实际业务开发过程中,我们可能会经常遇到两个表互相关联匹配,根据关联列更新某些特定字段的场景。如果我们使用INSERT和UPDATE则需要将表进行多次扫描判断,当基表数据量很大时,这种方式效率是低的,而且繁琐。而SQL语法中的MERGE功能精悍的关键字,它就是专门应对这种场景而出现的,merge同时拥有insert和update的属性,让我们用一个sql语句就可以在这种场景下做到“有则更新,无则插入”。Merge语法是SQL2003标准引入的,现在大部分主流数据库都是好支持的,达梦作为国产数据库的前排兵,当然也是能很好支持merge语法的。下面我们通过案例实践来看看如何在达梦数据库中将merge into用好用快,在此之前我们将需要关注的几个参数列出来:

参数名称 所属位置
BATCH_PARAM_OPT dm.ini
BATCH_ERRORS_ADAPTIVE /etc/dm_svc.conf
OCI_BATCH_ERRORS OCI接口(OCIStmtExecute的mode属性)

2.测试环境:

主机 VMWARE 16
操作系统 Redhat6
数据库版本 V8 03134283950-20221121-175072-20024

3.测试条件:
    我们使用默认初始化参数在测试环境上测试,测试程序模拟应用对表进行merge入库50000条数据,使用批量绑定方式操作,每个批次500条绑定提交,共100个批次串行执行。为了说明问题,测试程序中第一批次中故意设置了两条重复数据,而后面99批次的数据都是唯一的。(这一点很关键,直接影响后续是否正常入库和入库性能),测试表定义如下:

create table merge_test
(
C1 varchar2(8)  null,
C2 varchar2(8)  null,
C3 varchar2(16)  null,
C4 varchar2(8)  null,
C5 number(12,2)  null,
C6 number(12,0)  null,
C7 number(12,0)  null,
C8 number(12,0)  null,
C9 number(12,0)  null,
C10 number(12,2) default 0  null,
not cluster primary key(C3,C2,C4,C1)
);

使用的测试语句SQL为:

merge into merge_test using dual on (C1=:C1 and C2=:C2 and C3=:C3 and C4=:C4) when not matched then insert ( C1, C2, C3, C4) values (:C1,:C2,:C3,:C4) when matched then update set C5 =null,C6=null,C7=null,C8=null,C9=null,C10=null

4.开始对比测试
4.1 关闭批量优化性能
    首先我们使用初始化实例的默认参数来跑一下测试程序,看看总耗时:
image.png
image.png
默认参数中BATCH_PARAM_OPT=0,在没有开批量优化时数据其实是一行行处理的,虽然第一批次中有两条重复数据,但merge对于这两条重复在内部的处理方式实际上是第一条insert而第二条update,所以执行过程完全正常,数据总量为49999条符合预期。
4.2 开启批量优化参数
    为了提升入库性能,开启批量入库优化参数BATCH_PARAM_OPT=1,再次执行测试程序:
image.png
image.png
    可以看到此时,重复那一个批次的数据虽然只有一条数据重复,但是该批次的数据都没有入库成功(也就是放弃了499条数据),这是符合预期的。因为开启批量优化后服务器做批量处理,而第一个批次中数据有两条重复,报错被回滚掉了,所以最终入库数据总量为49500。同时我们可以看到入库的性能也的确提升上来了,但是缺点是有重复那个批次的数据全部丢失了。
4.3 如何避免报错
    但是实际业务场景中我们不能保证每个批次中的数据都是唯一的,但是又要求不要丢数据该怎么办呢?对于OCI接口OCIStmtExecute函数的mode参数,该参数可以指定执行时的模式,该属性存在OCI_BATCH_ERRORS的值,该属性值是为了兼容oracle的,它可以在数据批处理的时,如果某一条记录失败了,它会继续入库剩下的纪录,所以设置该模式后批量入库可以忽略报错,而且不会丢弃有重复数据批次的数据,但是可以看出入库性能明显下降了,这个入库性能基本与没有开批量优化的性能持平了。
image.png
image.png
image.png
4.4 “鱼与熊掌”可以兼得
    那怎么做到有重复数据不报错的同时,还能达到走批量的性能呢?带着这个想法,我们能否做到当同一批次没有重复数据时走批量入库,而有重复数据时变成一条条处理呢?参数BATCH_ERRORS_ADAPTIVE=(1)就是为了达到这个而出现的,我们需要将它加到/etc/dm_svc.conf配置文件中。测试前将OCIStmtExecute的mode修改为默认的OCI_DEFAULT。
image.png
image.png
可以看到既没有报错,也达到了走批量的性能,数据也没有发生丢失。
image.png
    从这里可以看出,如果应用程序设置了BATCH_ERRORS_ADAPTIVE=(1)时,merge语句的批量参数在OCI程序未使用OCI_BATCH_ERROS模式且执行报错违反唯一性约束的情况下,内部会重新以OCI_BATCH_ERROS的方式重新执行。换句话说,当有重复数据的批次数占比总批次数很小时时,总体入库性能也会无限接近于BATCH_PARAM_OPT=1的性能,而当有重复数据批次数无限接近总批次数(即绝大部分批次都有重复数据)时,总体性能会无限接近于BATCH_PARAM_OPT=0的入库性能。
4.5 单车变摩托
    这里值得一说的是,最新版本对于merge并发操作场景我们可以修改ONE_GROUP_SIZE=32,可以消除merge并发操作时hash槽初始化热点问题,从而进一步提升入库性能。
image.png
image.png

5.如何确定OCI应用是否开启OCI_BATCH_ERROS模式:
    现在我们知道影响merge入库的关键因素了,那当应用merge操作入库很慢时,我们如何确定应用代码中是否使用了OCI_BATCH_ERROS模式呢。第一种方法是直接与应用开发商进行确认,但这种方式很被动且不准确。第二种方式是我们掌握主动权进行确认,开启接口日志分析一下DPI/OCI日志即可(这里不在赘述开启方法):
image.png
image.png
    从达梦程序员手册和DPI.h联合起来分析我们可以看出此次入库接口启用了OCI_BATCH_ERRORS属性。
image.png
image.png
image.png
    根据DPI/OCI日志我们可以很明确看出应用代码中设置了OCI_BATCH_ERRORS属性。所以DPI/OCI日志也是一项能很好帮助我们分析问题的工具,实际工作中要灵活运行,仅用于问题排查,确认结束后要及时关闭接口日志。

6.总结:
    通过上述分析我们可以看出,达梦数据库在merge操作上还是有一些东西需要设置的。当然受制于测试环境条件的限制,对于merge批量入库的优化还远远不止如此,例如参数设置,物理磁盘性能等影响,本文仅仅是通过该用例说明这些参数对于merge操作的影响,这些影响可能涉及到数据、可能涉及到入库性能,我们要理解这些参数在背后所起的作用,在实际项目应用中才能去用好这些参数,以便在生产环境中发挥更大的作用。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服