专栏名称: 数据分析与开发
伯乐在线旗下账号,分享数据库相关技术文章、教程和工具,另外还包括数据库相关的工作。偶尔也谈谈程序员人生 :)
目录
相关文章推荐
51好读  ›  专栏  ›  数据分析与开发

为什么忘记 commit 也会造成 select 查询的性能问题

数据分析与开发  · 公众号  · 数据库  · 2016-09-13 20:53

正文

(点击 上方蓝字 ,快速关注我们)


来源:潇湘隐者

网址: www.cnblogs.com/kerrycode/p/5836015.html


今天遇到一个很有意思的问题,一个开发人员反馈在测试服务器ORACLE数据库执行的一条简单SQL语句非常缓慢,他写的一个SQL没有返回任何数据,但是耗费了几分钟的时间。让我检查分析一下原因,分析解决过后,发现事情的真相有点让人哭笑不得,但是也是非常有意思的。我们先简单构造一下类似的案例,当然只是简单模拟。


假设一个同事A,创建了一个表并初始化了数据(实际环境数据量较大,有1G多的数据),但是他忘记提交了。我们简单模拟如下:


SQL > create table test_uncommit

2 as

3 select * from dba_objects where 1 = 0;

Table created.

SQL > declare rowIndex number;

2 begin

3 for rowIndex in 1..70 loop

4 insert into test_uncommit

5 select * from dba_objects;

6 end loop ;

7 end ;

8 /

PL / SQL procedure successfully completed.

SQL >



另外一个同事B对这个表做一些简单查询操作,但是他不知道同事A的没有提交INSERT语句,如下所示,查询时间用了大概5秒多(这个因为构造的数据量不是非常大的缘故。实际场景耗费了几分钟)


SQL > SET TIMING ON ;

SQL > SET AUTOTRACE ON ;

SQL > SELECT COUNT (1) FROM SYS.TEST_UNCOMMIT WHERE OBJECT_ID = 39;

COUNT (1)

----------

0

Elapsed: 00:00:05.38

Execution Plan

----------------------------------------------------------

Plan hash value : 970680813

------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 13 | 6931 (3)| 00:00:10 |

| 1 | SORT AGGREGATE | | 1 | 13 | | |

|* 2 | TABLE ACCESS FULL | TEST_UNCOMMIT | 1 | 13 | 6931 (3)| 00:00:10 |

------------------------------------------------------------------------------------

Predicate Information ( identified by operation id):

---------------------------------------------------

2 - filter( "OBJECT_ID" =39)

Note

-----

- dynamic sampling used for this statement

Statistics

----------------------------------------------------------

4 recursive calls

0 db block gets

229304 consistent gets

61611 physical reads

3806792 redo size

514 bytes sent via SQL * Net to client

492 bytes received via SQL * Net from client

2 SQL * Net roundtrips to / from client

0 sorts ( memory )

0 sorts (disk)

1 rows processed

SQL >



当时是在SQL Developer工具里面分析SQL的执行计划,并没有注意到redo size非常大的情况。刚开始怀疑是统计信息不准确导致,手工收集了一下该表的统计信息,执行的时间和执行计划依然如此,没有任何变化。 如果我们使用SQL*Plus,查看执行计划,就会看到redo size异常大,你就会有所察觉(见后面分析)


SQL > exec dbms_stats.gather_table_stats( 'SYS' , 'TEST_UNCOMMIT' );

PL / SQL procedure successfully completed.

Elapsed: 00:00:12.29


因为ORACLE里面的写不阻塞读,所以不可能是因为SQL阻塞的缘故,然后我想查看这个表到底有多少记录,结果亮瞎了我的眼睛,记录数为0,但是空间用掉了852 个数据块


SQL > SELECT TABLE_NAME, NUM_ROWS, BLOCKS FROM DBA_TABLES WHERE TABLE_NAME= 'TEST_UNCOMMIT' ;

TABLE_NAME NUM_ROWS BLOCKS

---------------------------- -- ---------- ----------

TEST_UNCOMMIT 0 852

SQL







请到「今天看啥」查看全文