您的位置:首页 > 数据库 > Oracle

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

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

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

SQL>createtabletest_uncommit

2as

3select*fromdba_objectswhere1=0;


Tablecreated.


SQL>declarerowIndexnumber;

2begin

3forrowIndexin1..70loop

4insertintotest_uncommit

5select*fromdba_objects;

6endloop;

7end;

8/


PL/SQLproceduresuccessfullycompleted.


SQL>






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

SQL>SETTIMINGON;

SQL>SETAUTOTRACEON;

SQL>SELECTCOUNT(1)FROMSYS.TEST_UNCOMMITWHEREOBJECT_ID=39;


COUNT(1)

----------

0


Elapsed:00:00:05.38


ExecutionPlan

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

Planhashvalue:970680813


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

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

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

|0|SELECTSTATEMENT||1|13|6931(3)|00:00:10|

|1|SORTAGGREGATE||1|13|||

|*2|TABLEACCESSFULL|TEST_UNCOMMIT|1|13|6931(3)|00:00:10|

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

PredicateInformation(identifiedbyoperationid):

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

2-filter("OBJECT_ID"=39)


Note

-----

-dynamicsamplingusedforthisstatement



Statistics

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

4recursivecalls

0dbblockgets

229304consistentgets

61611physicalreads

3806792redosize

514bytessentviaSQL*Nettoclient

492bytesreceivedviaSQL*Netfromclient

2SQL*Netroundtripsto/fromclient

0sorts(memory)

0sorts(disk)

1rowsprocessed


SQL>






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

SQL>execdbms_stats.gather_table_stats('SYS','TEST_UNCOMMIT');


PL/SQLproceduresuccessfullycompleted.


Elapsed:00:00:12.29


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

SQL>SELECTTABLE_NAME,NUM_ROWS,BLOCKSFROMDBA_TABLESWHERETABLE_NAME='TEST_UNCOMMIT';


TABLE_NAMENUM_ROWSBLOCKS

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

TEST_UNCOMMIT0852


SQL>






于是我使用Tom大师的show_space脚本检查、确认该表的空间使用情况,如下所示,该表确实使用852个数据块。

SQL>setserverouton;

SQL>execshow_space('TEST_UNCOMMIT');

FreeBlocks.............................852

TotalBlocks............................896

TotalBytes.............................7,340,032

TotalMBytes............................7

UnusedBlocks...........................43

UnusedBytes............................352,256

LastUsedExtFileId....................1

LastUsedExtBlockId...................88,201

LastUsedBlock.........................85


PL/SQLproceduresuccessfullycompleted.


SQL>






分析到这里,那么肯定是遇到了插入数据操作,却没有提交的缘故。用下面脚本检查发现一个会话ID为883的对这个表有一个ROW级排他锁,而且会话还有一个事务排他锁,那么可以肯定这个会话执行了DML操作,但是没有提交。

SETlinesize190

COLosuserformata15

COLusernameformata20wrap

COLobject_nameformata20wrap

COLterminalformata25wrap

COLreq_modeformata20

SELECTB.SID,

C.USERNAME,

C.OSUSER,

C.TERMINAL,

DECODE(B.ID2,0,A.OBJECT_NAME,

'TRANS-'

||TO_CHAR(B.ID1))OBJECT_NAME,

B.TYPE,

DECODE(B.LMODE,0,'WAITING',

1,'NULL',

2,'Row-S(SS)',

3,'ROW-X(SX)',

4,'SHARE',

5,'S/ROW-X(SSX)',

6,'EXCLUSIVE',

'OTHER')"LOCKMODE",

DECODE(B.REQUEST,0,'',

1,'NULL',

2,'Row-S(SS)',

3,'ROW-X(SX)',

4,'SHARE',

5,'S/ROW-X(SSX)',

6,'EXCLUSIVE',

'OTHER')"REQ_MODE"

FROMDBA_OBJECTSA,

V$LOCKB,

V$SESSIONC

WHEREA.OBJECT_ID(+)=B.ID1

ANDB.SID=C.SID

ANDC.USERNAMEISNOTNULL

ORDERBYB.SID,

B.ID2;






我们在会话里面提交后,然后重新执行这个SQL,你会发现执行计划里面redosize为0,这是因为redosize表示DML生成的redolog的大小,其实从上面的执行计划分析redosize异常,就应该了解到一个七七八八了,因为一个正常的SELECT查询是不会在redolog里面生成相关信息的。那么肯定是遇到了DML操作,但是没有提交。





分析到这里,我们已经知道事情的前因后果了,解决也很容易,找到那个会话的信息,然后定位到哪个同事,让其提交即可解决。但是,为什么没有提交与提交过后的差距那么大呢?是什么原因呢?我们可以在这个案例,提交前与提交后跟踪执行的SQL语句,如下所示。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  oracle
相关文章推荐