2023-02-17 ORACLE SQL 優(yōu)化筆記

查看執(zhí)行計(jì)劃的方法:

這種方式看到的執(zhí)行計(jì)劃不一定是真實(shí)的哮伟,現(xiàn)在很少用了:

explain plan for select * from tab;

select * from table(dbms_xplan.display());

這種會執(zhí)行SQL:

set autotrace on

select * from tab where rownum<1;

這種不會執(zhí)行SQL:

set autotrace traceonly exp

select * from tab where rownum<10;

這種是最真實(shí)的執(zhí)行計(jì)劃:

alter session set sql_trace=true;

select * from tab where rownum<10;

alter session set sql_trace=false;

用 ls -lt | head 來查找生成的文件

用tkprof來解讀文件

last_call_et:表示會話目前已經(jīng)執(zhí)行了多長時間,單位是秒

select sql_id,program,username,last_call_et from v$session where type !='BACKGROUND' and status='ACTIVE';

select * from table(dbms_xplan.display_cursor('gvg0yjnt9dk6f',null));

獲取某個SQL的sql_id:

select sql_id from v$sql where sql_text like 'select count(*) from dba_objects';

select * from table(dbms_xplan.display_cursor('fk7j3tnpandph',null,'ALLSTATS'));

顯示上一個執(zhí)行的SQL的執(zhí)行計(jì)劃:

select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS'));

select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));


----select sql_id from dba_hist_sqlstat where plan_hash_value !=0 and rownum<10;

如果通過AWR已經(jīng)獲取了SQL_ID亲善,則可以直接得到執(zhí)行計(jì)劃:

select * from table(dbms_xplan.display_awr('sql_id'));

select * from table(dbms_xplan.display_cursor('sql_id',null,'ADVANCED ALLSTATS LAST PEEKED_BINDS'));

查看SQL的歷史執(zhí)行計(jì)劃:

select * from table(dbms_xplan.display_awr('6pkd06hdx99xk'));

select * from table(dbms_xplan.display_cursor('6pkd06hdx99xk',null,'ADVANCED ALLSTATS LAST PEEKED_BINDS'));

獲取SQL的一個綁定變量:

SELECT VALUE_STRING FROM v$sql_bind_capture WHERE sql_id ='6pkd06hdx99xk';

SELECT snap_id,NAME,position,value_string,last_captured,WAS_CAPTURED FROM dba_hist_sqlbind WHERE sql_id ='c1j018vt5ajdu';


select sql_id,sql_plan_line_id,sql_plan_hash_value,count(*)?

from? v$active_session_history

where sql_id='&sqlid'

group by sql_id,sql_plan_line_id,sql_plan_hash_value;

歷史的會話信息:

select sql_id,sql_plan_line_id,sql_plan_hash_value,count(*)?

from? dba_hist_active_sess_history

where sql_id='&sqlid'

group by sql_id,sql_plan_line_id,sql_plan_hash_value;?

select a.sql_id,a.sql_plan_line_id,a.sql_plan_hash_value,count(*)?

from dba_hist_active_sess_history a,dba_hist_sqlstat b?

where a.instance_number=b.instance_number and a.snap_id=b.snap_id

and a.dbid=b.dbid and a.sql_id=b.sql_id and a.sql_id='&sqlid'?

group by a.sql_id,a.sql_plan_line_id,a.sql_plan_hash_value;

查看等待事情的情況:

select event,count(distinct session_id),count(*) from v$active_session_history where sql_id='92b382ka0qgdt' group by event;

如果知道SQL_ID,則通過下面的方法獲取執(zhí)行計(jì)劃:

select * from table(dbms_xplan.display_cursor('&sql_id',null,'PEEKED_BINDS'));

v$active_session_history

dba_hist_active_sess_history

找到執(zhí)行計(jì)劃哪一步是瓶頸:

select? count(*),sql_plan_line_id,sql_plan_hash_value,sql_id?

from? gv$active_session_history?

where? sql_id='92b382ka0qgdt'?

group by sql_plan_line_id,sql_plan_hash_value,sql_id?

order by 2;

找到執(zhí)行計(jì)劃哪一步是瓶頸棺滞,簡單版:

select count(*),sql_plan_line_id?

from? gv$active_session_history?

where sql_id='92b382ka0qgdt'?

group by sql_plan_line_id?

order by 2;

找到執(zhí)行計(jì)劃哪一步是瓶頸,簡單版:

select count(*),sql_plan_line_id,sql_plan_hash_value?

from? gv$active_session_history?

where sql_id='92b382ka0qgdt'?

group by sql_plan_line_id,sql_plan_hash_value?

order by 2;

1、定位SQL

2贸街、顯示執(zhí)行計(jì)劃

3、定位 plan_line_id

4狸相、針對性優(yōu)化

1薛匪、定位SQL

2、顯示執(zhí)行計(jì)劃

3脓鹃、尋找歷史執(zhí)行計(jì)劃

4逸尖、綁定歷史執(zhí)行計(jì)劃

如果索引有問題的話,就查詢索引的情況:

col index_name for a40

col collist for a80

select index_name,listagg(column_name,',') within group(order by column_position) as collist?

from dba_ind_columns

where table_name = '&tname'

group by index_name

/

HIT:

/*+ NO_MERGE */? ? ----no_merge表示視圖不合并瘸右,merge表示視圖合并

/*+ leading(TMP) */

/*+ CARDINALITY(B,34343434343) */

/*+ gather_plan_statistics */

dbms_monitor.report_sql_monitor?

display_cursor(format=>'IOSTATS')

下面3個視圖的結(jié)構(gòu)基本一致:

v$sql

v$sqlstats

dba_hist_sqlstat 這個表中都是delta數(shù)據(jù):elapsed_time_delta娇跟,BUFFER_GETS_DELTA,EXECUTIONS_DELTA太颤,ROWS_PROCESSED_DELTA

sql_id

plan_hash_value

elapsed_time

elapsed_time_delta

BUFFER_GETS

BUFFER_GETS_DELTA

EXECUTIONS

EXECUTIONS_DELTA

ROWS_PROCESSED

ROWS_PROCESSED_DELTA

查看統(tǒng)計(jì)信息:

select sql_id,plan_hash_value,

sum(elapsed_time) els,

sum(elapsed_time)/greatest(sum(executions),1) els_per_exec,

sum(buffer_gets) gets,

sum(buffer_gets)/greatest(sum(executions),1) get_per_exec,

sum(executions) execs,

sum(rows_processed) rowcnt,

sum(elapsed_time)/greatest(sum(rows_processed),1) els_per_row,

sum(buffer_gets)/greatest(sum(rows_processed),1) get_per_row

from? v$sqlstats

where

sql_id='&sqlid'

group by sql_id,plan_hash_value?

order by els_per_exec;

查看歷史的統(tǒng)計(jì)信息

select sql_id,plan_hash_value,

sum(elapsed_time_delta) els,

sum(elapsed_time_delta)/greatest(sum(executions_delta),1) els_per_exec,

sum(buffer_gets_delta) gets,

sum(buffer_gets_delta)/greatest(sum(executions_delta),1) get_per_exec,

sum(executions_delta) execs,

sum(rows_processed_delta) rowcnt,

sum(elapsed_time_delta)/greatest(sum(rows_processed_delta),1) els_per_row,

sum(buffer_gets_delta)/greatest(sum(rows_processed_delta),1) get_per_row

from dba_hist_sqlstat

where

sql_id='&sqlid'

group by sql_id,plan_hash_value?

order by els_per_exec;

綁定執(zhí)行計(jì)劃:

dbms_sqltune.import_sql_profile?

coe_profile.sql

查詢表的數(shù)據(jù)的分布情況:

select column_name,t.num_rows,c.NUM_NULLS,c.num_distinct?

from dba_tables t,dba_tab_columns c

where t.owner=c.owner and t.table_name=c.table_name and t.table_name='&tablename'

order by num_distinct;

查看表的每個列的數(shù)據(jù)分布情況:

select column_name,t.num_rows,c.NUM_NULLS,c.num_distinct?

from dba_tables t,dba_tab_columns c

where t.owner=c.owner and t.table_name=c.table_name and t.table_name='FBP_BOE_TYPE'

order by num_distinct;

----查詢執(zhí)行時間最長的SQL

select *

from (select sa.SQL_TEXT,

sa.SQL_FULLTEXT,

sa.EXECUTIONS "執(zhí)行次數(shù)",

round(sa.ELAPSED_TIME / 1000000, 2) "總執(zhí)行時間",

round(sa.ELAPSED_TIME / 1000000 / sa.EXECUTIONS, 2) "平均執(zhí)行時間",

sa.COMMAND_TYPE,

sa.PARSING_USER_ID "用戶ID",

u.username "用戶名",

sa.HASH_VALUE

from v$sqlarea sa

left join all_users u

on sa.PARSING_USER_ID = u.user_id

where sa.EXECUTIONS > 0

order by (sa.ELAPSED_TIME / sa.EXECUTIONS) desc)

where rownum <= 50;

select sid,serial#,username,schemaname,osuser,machine,terminal,program,owner,object_name,object_type,o.OBJECT_id

from dba_objects o,v$locked_object i,v$session s

where o.object_id=i.object_id and s.sid=i.session_id;

做SQL優(yōu)化一定要把范圍控制在最小范圍內(nèi)苞俘,控制在當(dāng)前SQL內(nèi)最好。

快速優(yōu)化SQL的方法:

1龄章、找到合適的歷史的執(zhí)行計(jì)劃吃谣,進(jìn)行綁定。

2做裙、找到執(zhí)行計(jì)劃的瓶頸岗憋,針對性優(yōu)化。

3菇用、使用合適的索引澜驮、連接順序、連接方法惋鸥。

性能問題的定位:原則就是盡可能小范圍分析問題

1杂穷、SQL層

如果能定位SQL就不要從會話層面分析

2、會話層

如果能從會話層定位就不要從系統(tǒng)層分析

V$SESSION,V$SESSTAT,V$SESSION_WAIT,V$SQL,V$LOCK,SQL_TRACE

3卦绣、系統(tǒng)層

如果無法定位任何性能問題耐量,從系統(tǒng)層面入手

AWR,TOP ,IOSTAT

分析一個孤立的AWR是沒有意義的滤港。要結(jié)合業(yè)務(wù)分析廊蜒,并且要對比正常時候的AWR來分析趴拧。

數(shù)據(jù)庫負(fù)載重并不一定有問題。

高效的SQL來自于對業(yè)務(wù)的理解和對SQL執(zhí)行過程的理解山叮。

CBO能夠做的事情非常少著榴。

AWR信息的來源表:

select table_name from dict where table_name like '%DBA_HIST_%';

AWR中DB_TIME:所有用戶操作數(shù)據(jù)庫的時間總和。比如有10個用戶每個用戶操作1分鐘屁倔,那么DB TIME 就是10分鐘脑又。

CURS/SESS :每個會話發(fā)出的SQL情況。

綁定變量在OLTP中使用锐借,在OLAP中沒有必要使用问麸。

OLTP關(guān)注的是內(nèi)存,OLAP關(guān)注的是I/O钞翔。

我們要關(guān)注的是前臺的等待事件:Foreground events

DB FILE SEQUENTIAL READ 的值比較大严卖,說明有大量的根據(jù)索引的查詢。

ASH報(bào)告間隔時間可以精確到分鐘布轿,因而ASH可以提供比AWR更詳細(xì)的關(guān)于歷史會話的信息哮笆,可以作為AWR的補(bǔ)充。

v$active_session_history? ? ? ----當(dāng)前會話的采樣數(shù)據(jù),1S鐘更新一下快照

dba_hist_active_sess_history? ----保留v$active_session_history再早的數(shù)據(jù)

如果是要會話層面很詳細(xì)的數(shù)據(jù)就要做ASH驮捍,如果你要整體的性能數(shù)據(jù)就要做AWR.

RAC的優(yōu)化設(shè)計(jì):業(yè)務(wù)分割

優(yōu)點(diǎn):避免數(shù)據(jù)在實(shí)例內(nèi)存間傳遞導(dǎo)致的性能下降疟呐。

缺點(diǎn):數(shù)據(jù)無法使用全部節(jié)點(diǎn)資源。

RAC正面:多個實(shí)例處理數(shù)據(jù)东且,充分利用系統(tǒng)資源

RAC負(fù)面:大量的數(shù)據(jù)需要在實(shí)例的內(nèi)存間傳遞,影響性能

如果Interconnect導(dǎo)致嚴(yán)重的性能下降本讥,就考慮把并行開在一個實(shí)例上珊泳。

如果充分利用資源,能夠提高性能拷沸,那么就把并行開在不同的實(shí)例上色查。

select name,value v$sysstat where name like '%global cache%';

性能優(yōu)化是一個和業(yè)務(wù)密切相關(guān)的過程,單純的數(shù)據(jù)庫層面優(yōu)化沒有前途撞芍。

只能從架構(gòu)上解決海量數(shù)據(jù)的存儲問題秧了。

HASH分區(qū)就是單純的把數(shù)據(jù)均勻的分布在各個分區(qū),基本與業(yè)務(wù)無關(guān)序无,這種分區(qū)用的比較少验毡。

主要是范圍分區(qū)和列表分區(qū)。

對于分區(qū)表盡量不要建立全局索引帝嗡。做DDL操作就會使全局索引無效晶通。要建立本地分區(qū)索引LOCAL INDEX。一個分區(qū)對應(yīng)一個索引哟玷。

做更新時就不會使本地分區(qū)索引無效狮辽。

全局索引和分區(qū)索引的性能基本是一樣的。

分區(qū)索引的目的在于數(shù)據(jù)的管理而非性能。

一個分區(qū)表上如果經(jīng)常有DDL操作喉脖,將會導(dǎo)致全局索引失效椰苟,需要對索引重建,此時創(chuàng)建分區(qū)索引更加適合树叽。

ORACLE發(fā)明分區(qū)表只是解決數(shù)據(jù)管理上的考慮尊剔,而在性能上只是附加的考慮。

exec dbms_stats.gather_table_stats(user,'t',method_opt =>'for all columns size 254');? ? ----收集統(tǒng)計(jì)信息菱皆,并加上直方圖的信息

method_opt:主要是用來做直方圖的

size 254:說明建立254個桶须误,最多只能建立254個桶

for all columns:說明對所有的列進(jìn)行直方圖統(tǒng)計(jì)

for all hidden columns: 統(tǒng)計(jì)你看不到列的直方圖

for all indexed columns: 統(tǒng)計(jì)所有索引列的統(tǒng)計(jì)信息

exec?dbms_stats.gather_table_stats(user,'t',method_opt=>'for?all?columns?size?1');? ----對表t收集統(tǒng)計(jì)信息但不創(chuàng)建直方圖

size?1:表示不創(chuàng)建直方圖

user_tab_modifications 跟蹤表的修改。

當(dāng)表的數(shù)據(jù)修改超過10%仇轻,ORACLE會重新分析京痢。

定時任務(wù) GATHER_STATS_JOB 負(fù)責(zé)重新收集過舊的統(tǒng)計(jì)信息。

查看系統(tǒng)默認(rèn)的任務(wù)的執(zhí)行情況:

select log_id,job_name,status,to_char(log_date,'DD-MON-YYYY HH24:MI') log_date?

from dba_scheduler_job_run_details where job_name='GATHER_STATS_JOB';

查看表的修改情況:

exec DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;

select inserts,updates,deletes,timestamp from user_tab_modifications where table_name='T';

exec dbms_stats.gather_table_stats(user,'t',CASCADE=>true);? ? ? ----將表和索引一起分析

exec dbms_stats.delete_table_stats(user,'t',CASCADE_parts=>false);? ? -----刪除表的統(tǒng)計(jì)信息

開啟增量統(tǒng)計(jì)信息:

exec dbms_stats.set_table_prefs('scott','cmp','INCREMENTAL','TRUE');

收集一次統(tǒng)計(jì)信息:

exec dbms_stats.gather_table_stats(ownname=>'scott',tabname=>'cmp');

直方圖:ORACLE對列上的數(shù)據(jù)的分布進(jìn)行統(tǒng)計(jì)分析篷店,對數(shù)據(jù)傾斜分布時很有用祭椰。

數(shù)據(jù)分布不均勻就表示數(shù)據(jù)傾斜。

直方圖的類型:頻率直方圖疲陕,高度平衡直方圖方淤。

動態(tài)采樣:

LEVEL 10:對所有數(shù)據(jù)進(jìn)行采樣分析

LEVEL 1-10:采樣的數(shù)據(jù)量逐級遞增

創(chuàng)建擴(kuò)展統(tǒng)計(jì)信息:

exec dbms_stats.gather_table_stats(OWNNAME =>'DAVE',TABNAME =>'DAVE',method_opt =>'for columns(object_name,object_type)');

exec dbms_stats.gather_table_stats(OWNNAME =>'DAVE',TABNAME =>'DAVE',method_opt =>'for columns(UPPER(STATUS))');

在海量數(shù)據(jù)的表中執(zhí)行DELETE將是一個災(zāi)難。

在OLAP中執(zhí)行計(jì)劃多變蹄殃。在OLTP中執(zhí)行計(jì)劃基本不變携茂。

soft-sfot-parse? -----游標(biāo)通道沒有關(guān)閉,直接使用游標(biāo)通道诅岩,不需要重新打開游標(biāo)

游標(biāo)指向一個SQL.

一條SQL第一次運(yùn)行就是父游標(biāo)讳苦,第二次運(yùn)行就是子游標(biāo)。

select sql_id,child_number,loads? from v$sql where sql_text='select * from emp where 1=0';

SQL的文本一樣那么父游標(biāo)就一樣吩谦。

查詢執(zhí)行計(jì)劃最慢的步驟:

select count(*),sql_plan_line_id

from gv$active_session_history

where sql_id='2vcdzpaknk46s'

group by sql_plan_line_id

order by 2;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸳谜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子式廷,更是在濱河造成了極大的恐慌咐扭,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滑废,死亡現(xiàn)場離奇詭異蝗肪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)策严,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門穗慕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妻导,你說我怎么就攤上這事逛绵』掣鳎” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵术浪,是天一觀的道長瓢对。 經(jīng)常有香客問我,道長胰苏,這世上最難降的妖魔是什么硕蛹? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮硕并,結(jié)果婚禮上法焰,老公的妹妹穿的比我還像新娘。我一直安慰自己倔毙,他們只是感情好埃仪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著陕赃,像睡著了一般卵蛉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上么库,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天傻丝,我揣著相機(jī)與錄音,去河邊找鬼诉儒。 笑死葡缰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的允睹。 我是一名探鬼主播运准,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缭受!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起该互,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤米者,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宇智,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔓搞,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年随橘,在試婚紗的時候發(fā)現(xiàn)自己被綠了喂分。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡机蔗,死狀恐怖蒲祈,靈堂內(nèi)的尸體忽然破棺而出甘萧,到底是詐尸還是另有隱情,我是刑警寧澤梆掸,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布扬卷,位于F島的核電站,受9級特大地震影響酸钦,放射性物質(zhì)發(fā)生泄漏怪得。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一卑硫、第九天 我趴在偏房一處隱蔽的房頂上張望徒恋。 院中可真熱鬧,春花似錦欢伏、人聲如沸入挣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽财岔。三九已至,卻和暖如春河爹,著一層夾襖步出監(jiān)牢的瞬間匠璧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工咸这, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夷恍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓媳维,卻偏偏與公主長得像酿雪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子侄刽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 查看執(zhí)行計(jì)劃的方法: 這種方式看到的執(zhí)行計(jì)劃不一定是真的: explain plan for select * f...
    ben_782f閱讀 237評論 0 0
  • 一般說來指黎,ORACLE中SQL的優(yōu)化,在很大程度上是對執(zhí)行計(jì)劃的調(diào)整州丹,因而學(xué)會如何查看執(zhí)行計(jì)劃就顯得尤為重要...
    wqh8384閱讀 3,267評論 0 4
  • 優(yōu)化器規(guī)則 優(yōu)化器根據(jù)統(tǒng)計(jì)信息和代價(jià)模型([RBO] 醋安、[CBO])為每個執(zhí)行計(jì)劃計(jì)算一個代價(jià),代價(jià)是對執(zhí)行計(jì)劃的...
    hafe閱讀 975評論 0 1
  • Oracle面試題之SQL tunting 1:列舉幾種表連接方式 答:一共有三種連接方式(SQL優(yōu)化)墓毒,嵌套循環(huán)...
    三少爺_賤閱讀 1,353評論 0 7
  • 安裝目錄插件吓揪,閱讀體驗(yàn)更佳!K啤柠辞!參考:http://www.reibang.com/p/a40ec70d9365...
    ChaunhewieTian閱讀 985評論 0 2