Oracle數據庫該如何着手優化一個SQL


這是個終極問題,因為優化本身的復雜性實在是難以總結的,很多時候優化的方法並不是用到了什么高深莫測的技術,而只是一個思想意識層面的差異,而這些都很可能連帶導致性能表現上的巨大差異。
所以有時候我們應該先搞清楚需求到底是什么,SQL本身是否合理,這些思考很可能會使優化工作事半功倍。而本文是假設SQL本身合理,從Oracle提供給我們的一些技術手段來簡單介紹下Oracle數據庫,該如何使用一些現有的技術來優化一個SQL執行的性能。

  1. 確定需要優化的SQL文本及當前SQL執行計划
  2. 確定SQL涉及的所有表及其索引的相關信息
  3. 運行SQL Tuning Advisor 得到調整建議供優化參考
  4. 收集表信息
  5. 收集索引信息
  6. SQL Profile
  7. 物化視圖

1. 確定需要優化的SQL文本及當前SQL執行計划

優化之前先確定好需要優化的SQL文本以及當前SQL的執行計划是什么樣,注意PL/SQL Developer這類工具F5看到的執行計划很可能並不准確。 相關內容參考: - [SQL Tuning 基礎概述01 - Autotrace的設定](http://www.cnblogs.com/jyzhao/p/3849893.html) - [SQL Tuning 基礎概述02 - Explain plan的使用](http://www.cnblogs.com/jyzhao/p/3850022.html) - [SQL Tuning 基礎概述03 - 使用sql_trace和10046事件跟蹤執行計划](http://www.cnblogs.com/jyzhao/p/3850047.html)

2. 確定SQL涉及的所有表及其索引的相關信息

確定查詢涉及到的所有表及其索引的相關基礎信息。比如: > 各表的數據量 > 表和索引類型 > 表分區信息,每個分區的數據量 > 索引字段 > 索引分區信息 > 表關聯方式 > 結果集的數量

確定相關信息,以T2表為例:

--普通表/分區表信息
select * from dba_tables where table_name = 'T2';
select * from dba_part_tables where table_name = 'T2'; 
--普通表/分區表的每個分區大約__G大小
select (t.bytes/1024/1024) "MB", t.* from dba_segments t where segment_name = 'T2';  

--表數據量信息
--普通表的數據量
select count(1) from T2; --____數據左右
--分區表的某個分區數據量
select count(*) from T2 partition(P20160101);  --____數據左右
select count(*) from T2 partition(P20160102);

--表索引信息
--普通表索引及各個索引的索引列
select * from dba_indexes where table_name = 'T2';
select * from dba_ind_columns where index_name in (select index_name from dba_indexes where table_name = 'T2')order by index_name, column_position;
--分區表索引及各個索引的索引列
select * from dba_part_indexes where table_name = 'T2';
select * from dba_ind_columns where index_name in (select index_name from dba_part_indexes where table_name = 'T2') order by index_name, column_position;
--索引段大小信息
--select (t.bytes/1024/1024) "MB", t.* from dba_segments t where segment_name in (select index_name from dba_part_indexes where table_name = 'T2') order by segment_name, partition_name;

相關內容參考:

3. 運行SQL Tuning Advisor 得到調整建議供優化參考

運行SQL Tuning Advisor 得到調整建議供優化參考, SQL Tuning Advisor得到的優化建議僅供參考,具體如何做還需要結合業務實際情況。

相關內容參考:

4. 收集表信息

例如收集ZJY用戶下T2表的統計信息。(T2是range分區表,按天分區,每天數據量大概80w,存放半年) ``` SQL> execute dbms_stats.gather_table_stats(ownname => 'ZJY', tabname => 'T2', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR ALL COLUMNS SIZE AUTO', cascade => TRUE, degree => 16);

PL/SQL procedure successfully completed

Executed in 5896.641 seconds

統計信息加鎖/解鎖

--鎖住表的統計信息
exec dbms_stats.lock_table_stats('ZJY','T2');
--解鎖表的統計信息
exec dbms_stats.unlock_table_stats('ZJY','T2');

相關內容參考:
- [【轉載】dbms_stats 導入導出表統計信息](http://www.cnblogs.com/jyzhao/articles/4746972.html)

<h1 id="5">5. 收集索引信息</h1>
例如只收集ZJY用戶下T2表的索引IDX_T2_1統計信息。(IDX_T2_1是分區索引,包含4個字段)

SQL> execute dbms_stats.gather_index_stats(ownname => 'ZJY', indname => 'IDX_T2_1', estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, degree => 8);

PL/SQL procedure successfully completed

Executed in 44.312 seconds

有時還很可能需要在業務閑時在線創建新的索引

--不記錄日志在線並行創建單列索引IDX_T2_2(並行度視生產環境當前的CPU資源使用情況來確定合理的值)
create index IDX_T2_2 on T2(start_time) tablespace DBS_I_JINGYU nologging parallel 12 online;
alter index IDX_T2_2 noparallel;
alter index IDX_T2_2 logging;

<h1 id="6">6. SQL Profile</h1>
SQL Profile是10g中的新特性,作為自動SQL調整過程的一部分。SQL Profile是一個對象,它包含了可以幫助查詢優化器為一個特定的SQL語句找到高效執行計划的信息。這些信息包括執行環境、對象統計和對查詢優化器所做評估的修正信息。它的最大優點之一就是在不修改SQL語句和會話執行環境的情況下影響查詢優化器的決定。SQL Profile中包含的並非單個執行計划的信息,SQL Profile不會固定一個SQL語句的執行計划。當表的數據增長或者索引創建、刪除,使用同一個SQL Profile的執行計划可能會改變,而存儲在SQL Profile中的信息會繼續起作用。所以,經過一段很長的時間之后,它的信息有可能會過時,需要重新生成。

相關內容參考:
- [【轉載】sql_profile的使用](http://www.cnblogs.com/jyzhao/articles/3766455.html)
- [【轉載】sql_profile快速綁定腳本](http://www.cnblogs.com/jyzhao/articles/3766713.html)
- [使用COE腳本綁定SQL Profile](https://www.cnblogs.com/jyzhao/p/9256293.html)

<h1 id="7">7. 物化視圖</h1>
Oracle的物化視圖可以用於預先計算並保存(表連接或聚集等耗時較多的操作的)結果,所以合理使用物化視圖,會在執行查詢時避免進行這些耗時的操作,從而快速的得到結果。

相關內容參考:
- [【轉載】物化視圖詳解](http://www.cnblogs.com/jyzhao/articles/5124141.html)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM