一条insert语句导致的性能问题分析(一)
生活随笔
收集整理的這篇文章主要介紹了
一条insert语句导致的性能问题分析(一)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
今天早上開發(fā)找我看一個問題,說他們通過程序連接去查一個表的數(shù)據(jù)的時候,只查到了8條記錄,這個情況著實比較反常,因為從業(yè)務(wù)上的數(shù)據(jù)情況來說,不可能只有8條。
但是開發(fā)沒有太多的權(quán)限做線上環(huán)境的數(shù)據(jù)檢查,就讓我?guī)兔匆幌隆?br /> 語句大概是下面這樣的形式。
select count(*) from TEST_VIP_LOG t where t.flag in(2,3) and insert_time >= to_date('2016-03-10','YYYY-MM-DD') and insert_time< to_date('2016-03-17','YYYY-MM-DD')
簡單運行之后,發(fā)現(xiàn)返回的結(jié)果是2萬多條記錄。
當然我這邊查詢的結(jié)果還是有一定的可靠性的。所以開發(fā)的這個問題就自然落到了我的頭上,為什么他們查看的數(shù)據(jù)只有8條,而我這邊的數(shù)據(jù)卻有2萬多條,這個問題聽起來確實有些蹊蹺,但是都是事出有因,簡單了解了一下事情的來龍去脈之后,原來他們是在早上八點程序自動連接去做的查詢,我查詢的時候已經(jīng)到了快10點,這個時間點里,一切皆有可能,但是為什么短時間內(nèi)會有這么大的數(shù)據(jù)變化呢,于是我查看了數(shù)據(jù)庫的負載情況,發(fā)現(xiàn)在八點左右確實有一些DB time的提升,查看sql方面的變化,也確實發(fā)現(xiàn)有一個job在運行,而運行的過程中會涉及這個表TEST_VIP_LOG的數(shù)據(jù)變更。看起來問題似乎是有了一些眉目。但是當我查看鎖的情況時,整個人都不好了。
$ sh showlock.sh
Current Locks
-------------
SID_SERIAL?? ORACLE_USERN OBJECT_NAME?????????????? LOGON_TIME?????????? SEC_WAIT OSUSER???? MACHINE????? PROGRAM????????????? STAT? STATUS???? LOCK_ MODE_HELD
------------ ------------ ------------------------- ------------------- --------- ---------- ------------ -------------------- ---------- ---------- ----- ----------
2655,14247?? SYS????????? TEST_VIP_LOG????????????? 2016-03-16 01:03:25???????? 0 oracle???? statg2.cyou. oracle@statg2.cyou.c WAITING??????? ACTIVE???? DML?? Row-X (SX)
可以看到有一個session還在active狀態(tài),而且相關(guān)的表正是test_vip_log,而且這個session是在凌晨1點登陸的,一直到了早上十點多還在運行。也就間接意味著運行了近10個小時。
關(guān)聯(lián)了一下對應(yīng)的session執(zhí)行的語句,發(fā)現(xiàn)是一條insert語句,竟然運行了近10個小時。
$ sh showsessql.sh 2655,14247
SQL_ID???????????????????????? SQL_TEXT
------------------------------ ------------------------------------------------------------
d1zs82wnrs52u????????????????? INSERT INTO TEST_VIP_LOG(CN,GRADE,RANK,SCORE,FLAG,INSERT_TIM
?????????????????????????????? E,OLD_RANK,SIGN,STATUS,TAG,OLD_SCORE) SELECT A.CN,A.GRADE,A.
?????????????????????????????? RANK,A.SCORE,DECODE(SIGN(A.RANK-(NVL(B.RANK,-1))),1,2,-1,3,0
?????????????????????????????? ,1), SYSDATE,(NVL(B.RANK,-1)),B.SIGN,B.FLAG,B.TAG,B.SCORE FR
?????????????????????????????? OM ( SELECT * FROM TEST_VIP_NEW MINUS SELECT * FROM TEST_VIP_NEW_BAK
?????????????????????????????? ) A LEFT JOIN TEST_VIP_NEW_BAK B ON A.CN=B.CN ??????????????????????????????????????????????????????????????????????????????????????????
然后就開始想這個語句是在幾個月以前有一個需求變更,里面有兩個表TEST_VIP_NEW和TEST_VIP_NEW_BAK做一些關(guān)聯(lián),然后把數(shù)據(jù)插入TEST_VIP_LOG,這個關(guān)聯(lián)看起來還是比較奇怪的。
我們來簡單看一看。
insert into TEST_vip_log(CN,GRADE,RANK,SCORE,FLAG,INSERT_TIME,OLD_RANK,sign,stat
us,TAG,OLD_SCORE)
??????? select? a.cn,a.GRADE,a.RANK,a.SCORE,DECODE(sign(a.rank-(NVL(b.rank,-1))),1,2,-1
,3,0,1),
??????? sysdate,(NVL(b.rank,-1)),b.sign,b.flag,b.tag,b.score
??????? from
??????? (
???????????? select * from TEST_vip_new minus select * from TEST_vip_new_bak
??????? ) a left join TEST_vip_new_bak b
??????? on a.cn=b.cn ;
首先test_vip_new會和test_vip_new_bak做一個minus操作,會以test_vip_new為基準匹配,然后得到的結(jié)果集再和test_vip_new_bak繼續(xù)匹配,左連接匹配。
總體來看這個映射關(guān)系沒有任何意義啊。可以做一個簡單的測試來說明。兩個表存在一個字段id,然后做匹配
SQL> create table a (id number);
Table created.
SQL> create table b (id number);
Table created.
SQL> insert into a values(1);
1 row created.
SQL> insert into a values(2);
1 row created.
SQL> insert into b values(1);
1 row created.
SQL> select * from a minus select * from b;
??????? ID
----------
???????? 2
minus之后得到的結(jié)果是id=2的記錄,然后再和表b映射,那么這種映射關(guān)系得到的結(jié)果是下面的形式。
SQL> select *from (select * from a minus select * from b) a left join b on a.id=b.id;
??????? ID???????? ID
---------- ----------
???????? 2
感覺這種表連接方式就是多余的,因為minus之后的結(jié)果,表b中肯定是沒有匹配的值,再一次關(guān)聯(lián)也實在是浪費。
然后回到原本的sql語句。
xxxx? (select * from TEST_vip_new minus select * from TEST_vip_new_bak
??????? ) a left join TEST_vip_new_bak b
??????? on a.cn=b.cn
這個表test_vip_new_bak反復(fù)關(guān)聯(lián),這個表的數(shù)據(jù)是怎么得來的呢,原來在job開始運行的時候就會重新初始化這個表的數(shù)據(jù)
execute immediate 'truncate table TEST_vip_new_bak';
insert /*+ append*/ into TEST_vip_new_bak select * from TEST_vip_new;
COMMIT;
按照目前的分析思路,可見test_vip_new里面的數(shù)據(jù)和test_vip_new_bak中的數(shù)據(jù)差別很小,為什么不直接去增量的數(shù)據(jù)呢。帶著疑問感覺好像找到了問題的關(guān)鍵,然后把開發(fā)的同學(xué)叫上來一起討論一番,其實對于我來說是比較好奇為什么會寫出那樣的表關(guān)聯(lián),當時是出于什么特別的考慮。
但是開發(fā)沒有太多的權(quán)限做線上環(huán)境的數(shù)據(jù)檢查,就讓我?guī)兔匆幌隆?br /> 語句大概是下面這樣的形式。
select count(*) from TEST_VIP_LOG t where t.flag in(2,3) and insert_time >= to_date('2016-03-10','YYYY-MM-DD') and insert_time< to_date('2016-03-17','YYYY-MM-DD')
簡單運行之后,發(fā)現(xiàn)返回的結(jié)果是2萬多條記錄。
當然我這邊查詢的結(jié)果還是有一定的可靠性的。所以開發(fā)的這個問題就自然落到了我的頭上,為什么他們查看的數(shù)據(jù)只有8條,而我這邊的數(shù)據(jù)卻有2萬多條,這個問題聽起來確實有些蹊蹺,但是都是事出有因,簡單了解了一下事情的來龍去脈之后,原來他們是在早上八點程序自動連接去做的查詢,我查詢的時候已經(jīng)到了快10點,這個時間點里,一切皆有可能,但是為什么短時間內(nèi)會有這么大的數(shù)據(jù)變化呢,于是我查看了數(shù)據(jù)庫的負載情況,發(fā)現(xiàn)在八點左右確實有一些DB time的提升,查看sql方面的變化,也確實發(fā)現(xiàn)有一個job在運行,而運行的過程中會涉及這個表TEST_VIP_LOG的數(shù)據(jù)變更。看起來問題似乎是有了一些眉目。但是當我查看鎖的情況時,整個人都不好了。
$ sh showlock.sh
Current Locks
-------------
SID_SERIAL?? ORACLE_USERN OBJECT_NAME?????????????? LOGON_TIME?????????? SEC_WAIT OSUSER???? MACHINE????? PROGRAM????????????? STAT? STATUS???? LOCK_ MODE_HELD
------------ ------------ ------------------------- ------------------- --------- ---------- ------------ -------------------- ---------- ---------- ----- ----------
2655,14247?? SYS????????? TEST_VIP_LOG????????????? 2016-03-16 01:03:25???????? 0 oracle???? statg2.cyou. oracle@statg2.cyou.c WAITING??????? ACTIVE???? DML?? Row-X (SX)
可以看到有一個session還在active狀態(tài),而且相關(guān)的表正是test_vip_log,而且這個session是在凌晨1點登陸的,一直到了早上十點多還在運行。也就間接意味著運行了近10個小時。
關(guān)聯(lián)了一下對應(yīng)的session執(zhí)行的語句,發(fā)現(xiàn)是一條insert語句,竟然運行了近10個小時。
$ sh showsessql.sh 2655,14247
SQL_ID???????????????????????? SQL_TEXT
------------------------------ ------------------------------------------------------------
d1zs82wnrs52u????????????????? INSERT INTO TEST_VIP_LOG(CN,GRADE,RANK,SCORE,FLAG,INSERT_TIM
?????????????????????????????? E,OLD_RANK,SIGN,STATUS,TAG,OLD_SCORE) SELECT A.CN,A.GRADE,A.
?????????????????????????????? RANK,A.SCORE,DECODE(SIGN(A.RANK-(NVL(B.RANK,-1))),1,2,-1,3,0
?????????????????????????????? ,1), SYSDATE,(NVL(B.RANK,-1)),B.SIGN,B.FLAG,B.TAG,B.SCORE FR
?????????????????????????????? OM ( SELECT * FROM TEST_VIP_NEW MINUS SELECT * FROM TEST_VIP_NEW_BAK
?????????????????????????????? ) A LEFT JOIN TEST_VIP_NEW_BAK B ON A.CN=B.CN ??????????????????????????????????????????????????????????????????????????????????????????
然后就開始想這個語句是在幾個月以前有一個需求變更,里面有兩個表TEST_VIP_NEW和TEST_VIP_NEW_BAK做一些關(guān)聯(lián),然后把數(shù)據(jù)插入TEST_VIP_LOG,這個關(guān)聯(lián)看起來還是比較奇怪的。
我們來簡單看一看。
insert into TEST_vip_log(CN,GRADE,RANK,SCORE,FLAG,INSERT_TIME,OLD_RANK,sign,stat
us,TAG,OLD_SCORE)
??????? select? a.cn,a.GRADE,a.RANK,a.SCORE,DECODE(sign(a.rank-(NVL(b.rank,-1))),1,2,-1
,3,0,1),
??????? sysdate,(NVL(b.rank,-1)),b.sign,b.flag,b.tag,b.score
??????? from
??????? (
???????????? select * from TEST_vip_new minus select * from TEST_vip_new_bak
??????? ) a left join TEST_vip_new_bak b
??????? on a.cn=b.cn ;
首先test_vip_new會和test_vip_new_bak做一個minus操作,會以test_vip_new為基準匹配,然后得到的結(jié)果集再和test_vip_new_bak繼續(xù)匹配,左連接匹配。
總體來看這個映射關(guān)系沒有任何意義啊。可以做一個簡單的測試來說明。兩個表存在一個字段id,然后做匹配
SQL> create table a (id number);
Table created.
SQL> create table b (id number);
Table created.
SQL> insert into a values(1);
1 row created.
SQL> insert into a values(2);
1 row created.
SQL> insert into b values(1);
1 row created.
SQL> select * from a minus select * from b;
??????? ID
----------
???????? 2
minus之后得到的結(jié)果是id=2的記錄,然后再和表b映射,那么這種映射關(guān)系得到的結(jié)果是下面的形式。
SQL> select *from (select * from a minus select * from b) a left join b on a.id=b.id;
??????? ID???????? ID
---------- ----------
???????? 2
感覺這種表連接方式就是多余的,因為minus之后的結(jié)果,表b中肯定是沒有匹配的值,再一次關(guān)聯(lián)也實在是浪費。
然后回到原本的sql語句。
xxxx? (select * from TEST_vip_new minus select * from TEST_vip_new_bak
??????? ) a left join TEST_vip_new_bak b
??????? on a.cn=b.cn
這個表test_vip_new_bak反復(fù)關(guān)聯(lián),這個表的數(shù)據(jù)是怎么得來的呢,原來在job開始運行的時候就會重新初始化這個表的數(shù)據(jù)
execute immediate 'truncate table TEST_vip_new_bak';
insert /*+ append*/ into TEST_vip_new_bak select * from TEST_vip_new;
COMMIT;
按照目前的分析思路,可見test_vip_new里面的數(shù)據(jù)和test_vip_new_bak中的數(shù)據(jù)差別很小,為什么不直接去增量的數(shù)據(jù)呢。帶著疑問感覺好像找到了問題的關(guān)鍵,然后把開發(fā)的同學(xué)叫上來一起討論一番,其實對于我來說是比較好奇為什么會寫出那樣的表關(guān)聯(lián),當時是出于什么特別的考慮。
總結(jié)
以上是生活随笔為你收集整理的一条insert语句导致的性能问题分析(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ImageServiceImpl加@Se
- 下一篇: 内置系统用户