前者很容易定位。所有的操作系統(tǒng)都可以讓我們查看 CPU 密集型任務(wù)。這些任務(wù)可以追溯到一個(gè)特定用戶,一個(gè)特定應(yīng)用程序模塊。 CPU 密集型模塊一般都是由較差的代碼和/或結(jié)構(gòu)造成,而不是性能差的 SQL。一旦確定模塊,你必須試圖使之更有效率。一個(gè)可能的解決方案是將把某些處理移除程序,讓數(shù)據(jù)庫(kù)處理(高明點(diǎn)的 SQL,存儲(chǔ)對(duì)象,內(nèi)聯(lián)函數(shù),數(shù)組處理等)。
第二個(gè)是 I/O 密集型的 SQL 語(yǔ)句。這些語(yǔ)句會(huì)導(dǎo)致大量的數(shù)據(jù)庫(kù) I/O(全表掃描,排序,更新等),并以很高代價(jià)運(yùn)行幾個(gè)小時(shí)。從 Oracle 7 開(kāi)始,解決了 SQL 識(shí)別問(wèn)題。通過(guò)查詢數(shù)據(jù)庫(kù)共享池區(qū)域,我們可以很容易確定大多數(shù) I/O 密集型 SQL 語(yǔ)句。
下面 SQL 語(yǔ)句演示了如何確定 I/O 命中率低于 80%的 SQL 語(yǔ)句。這個(gè)命中率是,自從 SQL 語(yǔ)句第一次被解析到共享池,通過(guò)所有執(zhí)行的語(yǔ)句反應(yīng)整體 I/O。下面可能是最近幾分鐘或幾天的結(jié)果:
代碼如下:
sql> SELECT executions,
2 disk_reads,
3 buffer_gets,
4 ROUND((buffer_gets - disk_reads) / buffer_gets, 2) hit_ratio,
5 sql_text
6 FROM v$sqlarea
7 WHERE executions > 0
8 AND buffer_gets > 0
9 AND (buffer_gets - disk_reads) / buffer_gets < 0.80
10 order by 4 desc ;
EXECUTIONS DISK_READS BUFFER_GETS HIT_RATIO SQL_TEXT
---------- ---------- ----------- ---------- -----------------------------------------------------------------------
16 180 369 .51 SELECT SKU,PREPACK_IND,CASE_ID,TRANSFER_QTY,UNIT_COST,UNIT_RETAIL,ROWID
FROM TSF_DETAIL WHERE transfer = :1 order by sku
16 30 63 .52 SELECT TRANSFER,TO_STORE,TO_WH FROM TSFHEAD WHERE TRANSFER = :b1 AND
TRANSFER_STATUS = 'A'
2 3 7 .57 SELECT SKU FROM UPC_EAN WHERE UPC = :b1
12 14 35 .60 SELECT SUBSTR(DESC_UP,1,30),DEPT,SYSTEM_IND FROM DESC_LOOK WHERE
SKU = :b1
14 13 35 .63 SELECT UNIT_COST,UNIT_RETAIL,SUBCLASS FROM WIN_SKUS WHERE SKU = :b1
事實(shí)上,我們發(fā)現(xiàn)對(duì)特定的 SQL,上面的數(shù)據(jù)有些誤導(dǎo),其實(shí)語(yǔ)句沒(méi)有問(wèn)題。考慮下面 v$sqlarea 輸出:
Executions Disk_Reads Buffer_Gets Hit_Ratio Sql_Text
---------- ---------- ----------- --------- --------------------
2 6 19 0.68 SELECT A.EMP_NO, ...
該語(yǔ)句的命中率很低,但事實(shí)上它很有效。因?yàn)?,SQL 是通過(guò) UNIQUE 索引操作的,物理磁盤讀取的數(shù)量幾乎與邏輯讀取一樣。UNIQUE 索引顯著減少了整體的物理和邏輯磁盤 I/O 數(shù)量,導(dǎo)致了一個(gè)令人誤解的低命中率。
下面例子,命中率很好。但是真的很好嗎?
代碼如下:
Executions Disk_Reads Buffer_Gets Hit_Ratio Sql_Text
---------- ---------- ----------- --------- --------------------
2 3625 178777 0.98 SELECT A.EMP_NO, ...
這個(gè) SQL 語(yǔ)句看上去很有效。但是, 當(dāng)我們仔細(xì)看時(shí),事情就不是那么回事了。命中率并沒(méi)有透露出,該語(yǔ)句存在五個(gè)表連接,并且每次執(zhí)行進(jìn)行了超過(guò) 3600 個(gè)物理磁盤讀取。這是否太多了?是否有效?若不進(jìn)一步研究,無(wú)法回答這兩個(gè)問(wèn)題。事實(shí)上,這個(gè)實(shí)例中,五個(gè)表的中其一個(gè)錯(cuò)誤地執(zhí)行了全表掃描。通過(guò)重新構(gòu)造 SQL,我們可以減少物理磁盤 I/O 到小于 50,同時(shí),也顯著減少邏輯磁盤 I/O。巧合的是,命中率也下降到不到 70%。
我們首選 V$SQLAREA 查詢是每個(gè)語(yǔ)句執(zhí)行的物理磁盤 I/O 的真實(shí)報(bào)告。命中率是信息性的,但有時(shí)會(huì)產(chǎn)生誤導(dǎo)。邏輯 I/O 相關(guān)的很少。如果語(yǔ)句執(zhí)行 1,000,000 個(gè)邏輯 I/O,但只用了不到十分之一秒,這就沒(méi)人在乎了。這是總的物理 I/O,幾乎消耗了所有的時(shí)間,和確定潛在不正確的 SQL。例如:
代碼如下:
sql> SELECT sql_text, executions,
ROUND(disk_reads / executions, 2) reads_per_run,
disk_reads, buffer_gets,
ROUND((buffer_gets - disk_reads)
/ buffer_gets, 2) hit_ratio,
sql_text
FROM v$sqlarea
WHERE executions > 0
AND buffer_gets > 0
AND (buffer_gets - disk_reads) / buffer_gets < 0.80
ORDER by 3 desc ;
前兩個(gè)語(yǔ)句會(huì)報(bào)告更具啟發(fā)性的結(jié)果:
代碼如下:
Executions Reads_Per_Run Disk_Reads Buffer_Gets Hit_Ratio Sql_Text
---------- ------------- ---------- ----------- --------- ------------
2 3 6 19 0.68 SELECT ...
2 1812.5 3625 178777 0.98 SELECT ...
從視圖 V$SQLAREA 中,我們可以立即隔離所有具有高物理讀取的語(yǔ)句。這些語(yǔ)句可能并不一定低效或?qū)懙貌缓?,但恰恰是它們需要進(jìn)一步調(diào)查或調(diào)整。
更多信息請(qǐng)查看IT技術(shù)專欄