Oracle高資源消耗SQL語(yǔ)句定位
Oracle高資源消耗SQL語(yǔ)句定位
http://www.ecdoer.com/post/oracle-highcost-sql-locate.html
Oracle SQL語(yǔ)句資源消耗監(jiān)控最常用的系統(tǒng)視圖有v$sql、v$sqlarea、v$sqltext和v$session。本文我們先了解這些視圖的作用與區(qū)別,然后了解如何定位高資源消耗SQL語(yǔ)句,最后再了解一下各視圖字段具體含義。
相關(guān)系統(tǒng)視圖功能與區(qū)別
v$sql和v$sqlarea基本相同,記錄了共享SQL區(qū)(share
pool)中SQL統(tǒng)計(jì)信息,如內(nèi)存消耗、IO(物理磁盤讀和邏輯內(nèi)存讀)、排序操作、哈希ID等數(shù)據(jù)。不同之處在于v$sql為每一條SQL保留一個(gè)條目,而v$sqlarea中根據(jù)sql_text(需要注意,該處存儲(chǔ)的為當(dāng)前SQL指針的前1000個(gè)字符,也就是說(shuō)這里記錄的SQL可能是不完整的?。┻M(jìn)行g(shù)roup
by,統(tǒng)計(jì)列進(jìn)行sum(),通過(guò)version_count計(jì)算子指針的個(gè)數(shù)。
然而,文本(sql_text)相同的SQL語(yǔ)句在數(shù)據(jù)庫(kù)中意義可能完全不同。比如數(shù)據(jù)庫(kù)中存在兩個(gè)用戶User1和User2,這兩個(gè)用戶各擁有一張數(shù)據(jù)表EMP。那么當(dāng)兩個(gè)用戶發(fā)出查詢select
count(*) from
emp;時(shí)各自訪問(wèn)自己SCHEMA中的表EMP,而兩者表內(nèi)容不同所以其資源消耗肯定也不同。此時(shí),在v$sql中會(huì)有這兩條完全一樣的SQL各自的統(tǒng)計(jì)信息,而在v$sqlarea中sql_text相同的2個(gè)指針會(huì)合并起來(lái),執(zhí)行次數(shù)、DISK_READS、BUFFER_GETS等統(tǒng)計(jì)信息都會(huì)累加(sum),version_count會(huì)顯示為2,這就是v$sqlarea的聚合作用。
v$sqltext中沒有統(tǒng)計(jì)信息,然而卻存儲(chǔ)著完整的SQL語(yǔ)句及其哈希ID等。
對(duì)于這三者,我們可以使用視圖v$fixed_view_definition來(lái)查看視圖的源表,如下:
SELECT view_definition FROM v$fixed_view_definition WHERE view_name='GV$SQL';
SELECT view_definition FROM v$fixed_view_definition WHERE view_name='GV$SQLAREA';
SELECT view_definition FROM v$fixed_view_definition WHERE view_name='GV$SQLTEXT';
注:視圖名為V$SQL但該視圖的源又是GV$SQL,所以直接使用GV$SQL,其他兩個(gè)也如此。
通過(guò)以上3條語(yǔ)句可以發(fā)現(xiàn),V$SQL數(shù)據(jù)來(lái)源X$KGLCURSOR_CHILD,其實(shí)數(shù)據(jù)還是來(lái)源于X$KGLOB;而V$SQLAREA數(shù)據(jù)來(lái)源X$KGLCURSOR_CHILD_SQLID本質(zhì)是對(duì)X$KGLCURSOR_CHILD按照sql_id等字段分組匯總后的結(jié)果;V$SQLTEXT數(shù)據(jù)來(lái)源X$KGLNA。
v$session主要用來(lái)確定會(huì)話相關(guān)信息,如通過(guò)SID和SERIAL#來(lái)唯一確定一個(gè)session(SID可能會(huì)重復(fù))、會(huì)話擁有者用戶名USERNAME、會(huì)話狀態(tài)(active:正在執(zhí)行SQL語(yǔ)句、inactive:等待操作、killed:被殺死)、會(huì)話由哪個(gè)客戶端發(fā)起(MACHINE、TERMINAL)、正在執(zhí)行什么SQL(通過(guò)SQL_ADDRESS、SQL_HASH_VALUE、SQL_ID、SQL_CHILD_NUMBER確定,有這些再借助v$sqltext就能知道)、甚至上一次執(zhí)行的SQL是什么(通過(guò)PREV_SQL_ADDRESS等確定)、鎖等待相關(guān)信息(如所在表、文件、塊、被鎖行)等。
高資源消耗SQL查找定位
1)查看讀硬盤多或占用內(nèi)存可能多的SQL:
select sql_text, disk_reads, buffer_gets, parsing_schema_name, executions
from v$sqlarea
order by disk_reads desc;
說(shuō)明:?jiǎn)渭儚腣$sqlarea中是無(wú)法查出每個(gè)SQL消耗的內(nèi)存量的,但我們可以借助磁盤讀次數(shù)間接反映可能的消耗內(nèi)存量較大的SQL語(yǔ)句,然后再借助執(zhí)行計(jì)劃(如v$sql_plan視圖)具體查看。
利用系統(tǒng)視圖v$sqlarea,其中disk_reads是磁盤讀次數(shù),也是主要字段,剩余字段均為參考字段。其中,buffer_gets是內(nèi)存讀次數(shù),parsing_schema_name是首次編譯者模式名(一般與user名相同),executions是語(yǔ)句執(zhí)行次數(shù)。
需要注意的是,v$sqlarea中sql_text可能不完整,若需要完整的則需要借助hash_value或sql_id結(jié)合v$sqltext來(lái)查看分析。
2)查看執(zhí)行次數(shù)多的SQL
select sql_text, executions, parsing_schema_name
from v$sqlarea
order by executions desc;
3)查看排序多的SQL
select sql_text, sorts, parsing_schema_name
from v$sqlarea
order by sorts desc;
該處還應(yīng)涉及Library Cache命中率、內(nèi)存命中率等內(nèi)容,暫不總結(jié),見轉(zhuǎn)載內(nèi)容“Oracle調(diào)優(yōu)相關(guān)的各種命中率、使用率匯總”。
相關(guān)視圖重要字段
v$sqlarea
v$sql和v$sqlarea基本類似,而v$sqlarea更常用,故僅對(duì)v$sqlarea常用字段進(jìn)行說(shuō)明,如下(個(gè)人參考Oracle官方文檔翻譯的,因是最新版本,所以會(huì)跟網(wǎng)絡(luò)上的有些出入):
-
SQL_TEXT:SQL語(yǔ)句的前1000個(gè)字符;
-
SQL_FULLTEXT:SQL語(yǔ)句的所有字符;
-
SQL_ID:緩存在高速緩沖區(qū)(library cache)中的SQL父游標(biāo)的唯一標(biāo)識(shí)ID(注,類似于hash_value,不過(guò)hash_value是4bytes而sql_id是8bytes,sql_id更精確后期可能會(huì)替代hash_value);
-
SHARABLE_MEM:SQL語(yǔ)句及其子游標(biāo)占用的共享內(nèi)存大?。?/strong>
-
PERSISTENT_MEM:打開SQL語(yǔ)句的生命周期內(nèi)所占用的固定內(nèi)存大?。ò佑螛?biāo));
-
RUNTIME_MEM:游標(biāo)執(zhí)行期間所占用的固定內(nèi)存大??;
-
SORTS:語(yǔ)句執(zhí)行導(dǎo)致的排序次數(shù);
-
VERSION_COUNT:在緩存中以該語(yǔ)句為父語(yǔ)句的子游標(biāo)總數(shù);
-
LOADED_VERSIONS:緩存中載入了這條語(yǔ)句上下文堆(KGL heap 6)的子游標(biāo)數(shù);
-
OPEN_VERSIONS:父游標(biāo)下打開的子游標(biāo)個(gè)數(shù);
-
USERS_OPENING:打開子游標(biāo)的用戶個(gè)數(shù);
-
FETCHES:SQL語(yǔ)句的fetch數(shù);
-
EXECUTIONS:包含所有子游標(biāo)在內(nèi)該SQL語(yǔ)句共執(zhí)行次數(shù);
-
USERS_EXECUTING:執(zhí)行過(guò)該語(yǔ)句所有子游標(biāo)的用戶總數(shù);
-
LOADS:語(yǔ)句被載入的總次數(shù);
-
FIRST_LOAD_TIME:父游標(biāo)被首次載入(編譯)的時(shí)間;
-
PARSE_CALLS:父游標(biāo)下所有子游標(biāo)解析調(diào)用次數(shù);
-
DISK_READS:該語(yǔ)句通過(guò)所有子游標(biāo)導(dǎo)致的讀磁盤次數(shù);
-
DIRECT_WRITES:該語(yǔ)句通過(guò)所有子游標(biāo)導(dǎo)致的直接寫入次數(shù);
-
BUFFER_GETS:該語(yǔ)句通過(guò)所有子游標(biāo)導(dǎo)致的讀緩存次數(shù);
-
APPLICATION_WAIT_TIME:應(yīng)用等待時(shí)間;
-
USER_IO_WAIT_TIME:用戶I/O等待時(shí)間;
-
PLSQL_EXEC_TIME:PLSQL執(zhí)行時(shí)間;
-
ROWS_PROCESSED:該SQL語(yǔ)句處理的總行數(shù);
-
OPTIMIZER_COST:此查詢優(yōu)化給出的成本數(shù);
-
PARSING_USER_ID:第一次解析該父語(yǔ)句的用戶ID;
-
PARSING_SCHEMA_ID:第一次解析該語(yǔ)句SCHEMA的ID;
-
PARSING_SCHEMA_NAME:解析該語(yǔ)句的SCHEMA的NAME;
-
KEPT_VERSIONS:指出是否當(dāng)前子游標(biāo)被使用DBMS_SHARED_POOL包標(biāo)記為常駐內(nèi)存;
-
ADDRESS:當(dāng)前游標(biāo)父句柄(唯一指向該游標(biāo)的一種地址編號(hào));
-
HASH_VALUE:該語(yǔ)句在library cache中hash值;
-
PLAN_HASH_VALUE:執(zhí)行計(jì)劃的hash值,可依此確定兩個(gè)執(zhí)行計(jì)劃是否相同(取代每行每字符進(jìn)行比較的方式);
-
CPU_TIME:該語(yǔ)句解析、執(zhí)行和fetch(取值)所消耗的CPU時(shí)間;
-
ELAPSED_TIME:該語(yǔ)句解析、執(zhí)行和fetch(取值)所經(jīng)過(guò)的時(shí)間;
-
LAST_ACTIVE_TIME:查詢計(jì)劃最后一次執(zhí)行的時(shí)間;
-
LOCKED_TOTAL:所有子游標(biāo)被鎖的次數(shù);'
v$sqltext
-
ADDRESS:當(dāng)前游標(biāo)父句柄(唯一指向該游標(biāo)的一種地址編號(hào));
-
HASH_VALUE:該游標(biāo)(子游標(biāo))在library cache中唯一hash值;
-
SQL_ID:緩存游標(biāo)中該SQL的一個(gè)唯一標(biāo)識(shí)值;
-
COMMAND_TYPE:SQL語(yǔ)句類型,如select、insert、update等;
-
PIECE:排序SQL文本的碎片數(shù);
-
SQL_TEXT:包含一個(gè)完整SQL中的某一小塊SQL文本字符(要完整的SQL語(yǔ)句需要把這些碎片組合起來(lái));
v$session
-
SADDR:session地址;
-
SID:session標(biāo)識(shí)值,常跟serial#聯(lián)合唯一確定一個(gè)session(在殺進(jìn)程時(shí),有時(shí)SID會(huì)重用,造成誤殺。而serial會(huì)增加但不會(huì)重復(fù),sid
在同一個(gè)instance的當(dāng)前session中是一個(gè)unique key,而sid
,serial#則是在整個(gè)instance生命期內(nèi)的所有session中是unique key);
-
SERIAL#:會(huì)話序列號(hào),用于在一個(gè)會(huì)話結(jié)束而另一個(gè)會(huì)話重用這該會(huì)話的SID時(shí),唯一確定一個(gè)會(huì)話;
-
AUDSID:審計(jì)會(huì)話ID,可以通過(guò)audsid查詢當(dāng)前session的sid,select sid from v$session where audsid=userenv('sessionid');
-
PADDR:進(jìn)程地址,關(guān)聯(lián)v$process的addr字段,通過(guò)這個(gè)可以查詢到進(jìn)程對(duì)應(yīng)的session;
-
USER#:同于dba_users中的user_id,Oracle內(nèi)部進(jìn)程user#為0;
-
USERNAME:會(huì)話擁有者用戶名,等于dba_users中的username,Oracle內(nèi)部進(jìn)程的username為空;
-
COMMAND:正在執(zhí)行的SQL語(yǔ)句類型,如1為create table、3為select等;
-
OWNERID:如果該列值為2147483644則值無(wú)效,否則值用于會(huì)話遷移、并行等;
-
TADDR:Address of transaction state object;
-
LOCKWAIT:標(biāo)識(shí)當(dāng)前查詢是否處于鎖等待狀態(tài),為空則表示無(wú)等待;
-
STATUS:標(biāo)識(shí)session狀態(tài),Active正執(zhí)行SQL語(yǔ)句,inactive等待操作,killed被標(biāo)注為殺死;
-
SERVER:服務(wù)器類型,DEDICATED專用、SHARED共享等;
-
SCHEMA#:SCHEMA標(biāo)識(shí)ID值,Oracle內(nèi)部進(jìn)程的schema#為0;
-
SCHEMANAME:SCHEMA用戶名,Oracle內(nèi)部進(jìn)程的為sys;
-
OSUSER:客戶端操作系統(tǒng)用戶名;
-
PROCESS:客戶端操作系統(tǒng)進(jìn)程ID;
-
MACHINE:操作系統(tǒng)機(jī)器名;
-
TERMINAL:操作系統(tǒng)終端名;
-
PROGRAM:操作系統(tǒng)應(yīng)用程序名,如EXE或sqlplus.exe;
-
TYPE:會(huì)話類型,如BACKGROUND或USER;
-
SQL_ADDRESS:和SQL_HASH_VALUE一起使用標(biāo)識(shí)正在執(zhí)行的SQL語(yǔ)句;
-
SQL_HASH_VALUE:和SQL_ADDRESS一起使用標(biāo)識(shí)正在執(zhí)行的SQL語(yǔ)句;
-
SQL_ID:正在執(zhí)行的SQL語(yǔ)句的標(biāo)識(shí)ID;
-
SQL_CHILD_NUMBER:正在執(zhí)行的SQL語(yǔ)句的子ID;
-
FIXED_TABLE_SEQUENCE:當(dāng)session完成一個(gè)user
call后就會(huì)增加的一個(gè)數(shù)值,也就是說(shuō),如果session掛起,它就不會(huì)增加。因此可以根據(jù)這個(gè)字段來(lái)監(jiān)控某個(gè)時(shí)間點(diǎn)以來(lái)的session性能情況。例如,一個(gè)小時(shí)前某個(gè)session的此字段數(shù)值為10000,而現(xiàn)在是20000,則表明一個(gè)小時(shí)內(nèi)其user
call較頻繁,可以重點(diǎn)關(guān)注此session的performance statistics。
-
ROW_WAIT_OBJ#:被鎖定行所在table的object_id,和dba_object中的object_id關(guān)聯(lián)可以得到被鎖定的table name;
-
ROW_WAIT_FILE#:被鎖定行所在的datafile id,和v$datafile中的file#關(guān)聯(lián)可以得到datafile name;
-
ROW_WAIT_BLOCK#:被鎖定的塊ID;
-
ROW_WAIT_ROW#:被鎖定的當(dāng)前行;
-
LOGON_TIME:登錄時(shí)間;