注册
关于SQL执行和获取结果集耗时问题的讨论
专栏/滴水藏海/ 文章详情 /

关于SQL执行和获取结果集耗时问题的讨论

yuao 2021/12/30 2464 5 0
摘要 举例说明FIRST_ROWS的作用,以及SQL在执行阶段和获取结果集阶段的关系

在实际场景中我们可能经常会遇到一个查询语句在数据库SQL日志中记录的时间很快,但是用户反映或在应用层面上反映出很慢,那这是怎么回事呢,我们该如何排查这个问题呢?其实这样“看似相互矛盾”的情况主要有一些几方面原因:

1.数据库服务端与应用所在客户端之间的网络比较差,网络延时很大导致,导致应用从数据库服务器获取结果很慢,这也是大部分场景下的原因;
2.应用页面的这个请求不是由这一个SQL完成的,可能会涉及多个事务的多个SQL共同完成的,这其中任何的一个SQL慢都会导致应用的这个请求响应慢;
3.可能确实跟这个SQL在数据库中执行慢有关,那为什么在log_commit日志中记录的时间是很快的呢?我们今天所要讨论的就是这一方面的原因。

关于FIRST_ROWS
首先我们来引入一个数据库配置参数FIRST_ROWS ,我们知道达梦数据库查询优化器的优化目标为最快响应时间,这个参数值决定优先返回多少条记录给用户,而不需要等待全部结果确定后再输出,默认是100,也就是服务端计算出只要够了100行记录就返回。
假设最终结果集行数为RESULT_NUM,那么:
(1)当RESULT_NUM<= FIRST_ROWS时,SQL的执行时间就是真正execute的时间,获取结果集的时间就是遍历结果集的时间;
(2)当RESULT_NUM> FIRST_ROWS时,SQL的执行时间就是execute计算出FIRST_ROWS行记录的时间,而获取结果集的时间包含了遍历结果集的时间和计算出后续批次数据的时间。换句话说当结果集超过FIRST_ROWS,后续批次的数据是边计算边获取的,这里的计算还是按照初始生成的计划进行计算的。事实上,从第二批次开始获取的结果集数据并不是固定行数的,而是由固定大小的消息包构成,这个消息包的大小由参数FETCH_PACKAGE_SIZE决定,默认为512K,该参数设置的大则后续每个批次FETCH包含的记录行数就多,该参数设置的小则后续每个批次FETCH包含的记录行数就少,一般为默认值即可。
到这里我们上述提到的问题就可以解答了,log_commit日志中记录的是计算出FIRST_ROWS行数据的执行时间,而不是计算出所有数据的时间。

举个例子:
例如对于一个最终结果有299行的查询SQL,当使用默认FIRST_ROWS=100时,我们知道需要分3批才能将数据全部获取完,fetch获取结果集的时间还包括了后两批数据计算时间和遍历结果集的时间:
2.png
当更改FIRST_ROWS=300时,对于只有299行记录的结果集一次性就能获取到,但是相应的执行时间变长了,因为需要将299行记录全部计算出来才能返回。
1.png
那么上述举例我是特地拿了一个执行慢的sql来说明,所以在这种场景下要想提升这个sql的整体性能,归根到底还是需要将SQL优化好,无论是执行阶段还是获取结果集阶段,SQL执行变快才是王道!

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服