|
发现应用程序慢,开始把目光放在检查商业逻辑的SQL上面,觉得没什么问题,但是执行时间大大超出我的预期。 后来询问开发人员,原来最初会取工单表里面的最近工单时间,最早工单时间来做对比。 根据经验,对索引字段做MAX或者MIN是很快的,因为索引是有序,优化器直接到索引头或者尾部去取rowid就可以了。 但是打开程序一看,SQLpreparement里面的句子是这样的: select min(billtime),MAX(billtime) from billcontent 觉得有问题了,一看执行计划,恍然大悟: Execution Plan ---------------------------------------------------------- Plan hash value: 1499044795 ----------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ----------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 8 | 5126 (3)| 00:01:02 | | | | 1 | SORT AGGREGATE | | 1 | 8 | | | | | | 2 | PARTITION RANGE SINGLE| | 7653K| 58M| 5126 (3)| 00:01:02 | 1 | 1 | | 3 | PARTITION LIST ALL | | 7653K| 58M| 5126 (3)| 00:01:02 | 1 | 21 | | 4 | INDEX FAST FULL SCAN| IDX_ANALYSE_CONTENT_2 | 7653K| 58M| 5126 (3)| 00:01:02 | 1 | 21 | ----------------------------------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 26745 consistent gets 是INDEX FAST FULL SCAN,26745 个一致读,5126 的Cost,大概查了一下,该索引拥有27632个块,现在对索引做了完全扫描。 对于一致读和Cost的计算方法,这里暂不多述。 只查一个极限值话: select min(billtime) from billcontent; Execution Plan ---------------------------------------------------------- Plan hash value: 4137395070 ---------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 8 | 3 (0)| 00:00:01 | | | | 1 | SORT AGGREGATE | | 1 | 8 | | | | | | 2 | PARTITION RANGE SINGLE | | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 1 | | 3 | PARTITION LIST ALL | | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 21 | | 4 | INDEX FULL SCAN (MIN/MAX)| IDX_ANALYSE_CONTENT_2 | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 21 | ---------------------------------------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 42 consistent gets 计划是INDEX FULL SCAN (MIN/MAX),(MIN/MAX)表明只会访问索引的头或尾,开销大大减小,只有42个一致读和极低的Cost,正常情况只能是 这个的两倍多。 马上动手改为 SELECT (select min(calltime) from analyse_content ), (select MAX(calltime) from analyse_content ) FROM dual Execution Plan ---------------------------------------------------------- Plan hash value: 2326664376 ---------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 2 (0)| 00:00:01 | | | | 1 | SORT AGGREGATE | | 1 | 8 | | | | | | 2 | PARTITION RANGE SINGLE | | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 1 | | 3 | PARTITION LIST ALL | | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 21 | | 4 | INDEX FULL SCAN (MIN/MAX)| IDX_ANALYSE_CONTENT_2 | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 21 | | 5 | SORT AGGREGATE | | 1 | 8 | | | | | | 6 | PARTITION RANGE SINGLE | | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 1 | | 7 | PARTITION LIST ALL | | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 21 | | 8 | INDEX FULL SCAN (MIN/MAX)| IDX_ANALYSE_CONTENT_2 | 7653K| 58M| 3 (0)| 00:00:01 | 1 | 21 | | 9 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | ---------------------------------------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 84 consistent gets 完美解决。 总结: 其实这个问题很小,这个SQL人人都会写,但是很多开发人员,在写这种SQL的时候不会去思考结果产生的过程,以实现为原则,在他们眼中数 据库仍然是黑盒。在测试过程中也没有仔细观察效率,在测试表数据较少,人眼感觉不出来问题,一在生产库跑就越来越慢。 所以,无论是开发和DBA多学习数据库的执行机制和原理,是没有害处的。
|
一共有 0 条评论