1. 程式人生 > >專項測試之SQL調優

專項測試之SQL調優

之前參與的敏捷專案中,開發在編碼之前,召集測試一起把設計文件過一遍,目的是通過溝通,儘早發現設計上的一些缺陷,避免放大效應。文件內容包括業務需求的具體實現,以及業務涉及的新表定義、DML、資料流,這種實踐對於測試的提早介入有重要意義,我們確實避免了許多問題,如新表設計的不合理、新表缺乏向下相容性、DML冗餘、DML效能問題、DML邏輯問題等等。敏捷專案對測試角色提出了更高的要求,今天主要講的是Oracle SQL調優,這是效能測試偏底層的知識,效費比不言而喻。

合理選擇基礎表

ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最後的表(基礎表)將被最先處理。 在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎表。

避免使用*

ORACLE在解析的過程中, 會將‘*’ 依次轉換成所有的列名, 這個工作是通過查詢資料字典完成的, 這意味著將耗費更多的時間

減少訪問次數

減少訪問佔用連線資源,減少網路IO、磁碟IO的次數,以下僅供參考
分散語句

select name from tableA where a_no = 1;
select name from tableB where b_no = 2;

合併語句

select a.name , b.name 
      from tableA a , tableB b,dual x 
      where nvl(x,x.dummy) = nvl
(x,a.rowid(+)) and nvl(x,x.dummy) = nvl(x,b.rowid(+)) and a.a_no (+) = 1 and b.b_no (+) = 2;

刪除資料

對於刪除重複資料,用rowid是最高效的

delete from tableA a where rowid != (select max(rowid) from tableB b where a.Prefix = b.Prefix);

對於刪除全表資料,用TRUNCATE替代DELETE。使用TRUNCATE,回滾段不再存放任何可被恢復的資訊,資料不能被恢復,因此執行時間也會很短。

delete from table;
--替換成
truncate from table;

養成使用別名的習慣

當在SQL語句中連線多個表時, 請使用表的別名,並把別名字首於每個Column上,以減少解析的時間並減少那些由Column歧義引起的語法錯誤。

表連線替換EXISTS

--低效
select ename 
      from emp e 
    where exists (select x 
               from dept 
             where dept_no = e.dept_no 
                 and dept_cat = a); 

--高效
select ename 
      from dept d,emp e 
    where e.dept_no = d.dept_no 
        and dept_cat = a ; 

EXISTS替換DISTINCT

--低效
select distinct d.dept_no, d.dept_name 
      from dept d,emp e 
      where d.dept_no = e.dept_no 

--高效
select d.dept_no, d.dept_name 
      from dept d 
    where exists (select x 
               from emp e 
             where e.dept_no = d.dept_no);

儘量避免耗費資源的操作

帶有DISTINCT、UNION、MINUS、INTERSECT、ORDER BY的SQL語句會啟動SQL引擎執行耗費資源的排序(SORT)功能。 DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序。

避免索引失效

避免改變索引列的型別:當比較不同資料型別的資料時, ORACLE自動對列進行簡單的型別轉換。當字元和數值比較時, ORACLE會優先轉換數值型別到字元型別。如果內部發生型別轉換, 這個索引將不會被用到。
避免在索引列上使用IS NULL和IS NOT NULL:對於單列索引,如果列包含空值,索引中將不存在此記錄;對於複合索引,如果每個列都為空,索引中同樣不存在此記錄。
避免在索引列上使用NOT:當ORACLE遇到NOT,他就會停止使用索引轉而執行全表掃描。
避免在索引列上使用計算:如果索引列是函式的一部分,將不使用索引而使用全表掃描。

--低效
select fieldfrom dept where val * 12 > 120

--高效
select fieldfrom dept 
    where val > 120/12

避免在索引列上使用函式:否則將停止使用索引而使用全表掃描。
避免在索引列上的第一個字元使用萬用字元:如果索引列所對應的值的第一個字元由萬用字元開始,索引將不被採用。在這種情況下,ORACLE將使用全表掃描。
避免索引列使用OR:對索引列使用OR將造成全表掃描。
使用索引的第一個列:如果索引是建立在多個列上,只有在它的第一個列被where子句引用時才會選擇使用該索引。
瞭解索引排他性:如果表中有兩個以上(包括兩個)索引,其中有一個唯一性索引,而其他是非唯一性。在這種情況下,ORACLE將使用唯一性索引而完全忽略非唯一性索引。

善用工具分析問題

PL/SQL、TOAD都集成了圖形化的EXPLAIN PLAN,這裡不再詳述