分享一个最近优化odb load性能的案例。
【先说结论】
odb可以设置parallel参数开启多个连接并行执行query,从而成倍的提升load性能。但是默认odbc接口函数 SQLExecute()在同一个进程内部是串行执行的。即虽然我们开启了多线程执行odb load,实际上还是串行执行,速率并没有显著提升。
可以通过配置/etc/odbcinst.ini文件,添加Threading=1选项,实现真正的并行,可以极大提升odb load性能。
|
[Trafodion]
Description = Trafodion ODBC Stand Alone Driver
Driver = /usr/lib64/libtrafodbc_drvr64.so
FileUsage = 1
UsageCount = 1
AppUnicodeType = utf16
Threading = 1 |
【load性能对比】
对于500万行lineitem表,原来我们的性能为2.3万行/s,而且parallel提升对性能影响不大,设置Threading=1后,性能随着parallel线性增长,可达27万行/s。
【分析过程】
odb load性能随着多线程的开启并没有明显增加,这点不符合咱们的常规认知,所以记录每个函数的时间,发现ODBC API SQLExecute函数存在蹊跷。
发现过程如下:
在qid statistics 中,发现每条insert query执行时间大概0.25s。
实验一、单线程执行odb时,记录每次SQLExecute执行时间,每次0.3s,符合预期。
实验二、开启两个线程,查看SQLExecute时间,出现一下现象。线程1执行第一次SQLExecute用时0.3s,正常。但是线程2比线程1晚开始一段时间,且SQLExecute执行了0.6s。后续T1执行第二遍时,由于T2正在执行所以也耗时0.6s。现象类似于SQLExecute在阻塞等待别的线程执行完毕。
实验三、为了验证实验二猜测,每个SQLExecute执行后,sleep 0.6s,为了使两个线程的SQLExecute不在同时执行,相互影响,得到以下结果。T1第一次SQLExecute耗时0.3s,符合预期,T1第一次0.6s,由于此时T1的SQLExecute正在执行,发生阻塞。稍后T2 sleep,T1在T2 sleep间隙执行了第二次SQLExecute,耗时0.3s,正常。后续T1和T2都在对方sleep的间隙执行函数SQLExecute,所以每次执行时间为0.3s,和qid statistics数据一致。
由此,定位到确实多线程执行SQLExecute函数发生阻塞。查阅MSDN,确实存在该情况的描述。
SQLExecute executes a statement prepared by SQLPrepare. After the application processes or discards the results from a call to SQLExecute, the application can call SQLExecute again with new parameter values.
【解决方法】
1. 使用设置ODBC handler异步的方法,可以实现SQLExecute函数不再阻塞。极大提升load性能。
2. 配置odbcinst.ini文件里的Threading=1参数,实现并行。这样不需要修改代码,而且性能对比下来要比异步实现SQLExecute好。
异步实现和设置Threading=1参数实现性能对比如下图:
这里解释下Threading=1的意思。
DM提供四种线程策略:
-
只有DM内部结构体受到线程保护;
-
线程保护为statement级别;
-
线程保护为connection级别;
-
线程保护在env级别,同一时间只有一个query在执行。
默认设置为0,驱动被设置为线程安全。
【结论】
所以说我们的odb性能是很棒的,只是我们不熟悉参数配置和很多细节,需要更加深入的学习和了解。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69985104/viewspace-2725834/
,如需转载,请注明出处,否则将追究法律责任。