1. 程式人生 > >高效能sql(摘自dw工作建議)

高效能sql(摘自dw工作建議)

1)SQL儘量不用order by語句。儘量使用DataStore中sort方法。

(2)使用EXIST代替IN可能會提高效能,但並非所有情況都適用。具體要依據測試結果而定。

示例:

//一般情況下,效率較低。

select …

from emp

where empno> 0

and deptno in (select deptno  from dept

   whereloc = 'melb')

//一般情況下,效率較高。

select …

from emp

where empno> 0

and exists ( select 'x' from dept

 where dept.deptno = emp.deptno

and loc = 'melb')

(3)使用NOT EXIST或外連線代替NOT IN可能會提高效能,但並非所有情況都適用。具體要依據測試結果而定。

示例:

//一般情況下,效率較低。

select …

from emp

where dept_no not in ( select dept_no

                                   from dept

  where dept_cat = 'a');

//一般情況下,效率較高。

select …

from employee e, department d

where e.dept_no = d.dept_no(+)

and d.dept_no is null

and d.dept_cat(+) = 'a'

//一般情況下最高效。

select …

from employee e

where not exists ( select 'x'

 from department d

 where e.dept_no = d.dept_no)

(4)用多表連線代替EXISTS子句;一般情況下,使用表連線替代 EXIST 子句可提高效能。

示例:

//一般情況下,效率較低。

select ename

from employee e

where exists ( select 'x'

  from department d     

                      where dept_no = e.dept_no

  and dept_cat = 'a');

//一般情況下,效率較高。

select ename

from department d, employee e

where d.dept_no = e.dept_no

and d.dept_cat = 'a';

(5)少用DISTINCT,用EXISTS代替。一般情況下,使用 EXIST 子句替代 DISTINCT 子句可提高效能。

示例:

//一般情況下,效率較低。

select distinct d.dept_no, d.dept_name

from department d,employee e

where d.dept_no = e.dept_no

//一般情況下,效率較高。

select dept_no, dept_name

from department d

where exists ( select 'x'

                      from employee e

                      where e.dept_no = d.dept_no);

(6)使用ROWID提高檢索速度。對SELECT得到的單行記錄,需進行DELETE、UPDATE操作時,使用ROWID將會使效率大大提高。

(7)查詢的WHERE過濾原則,應使過濾記錄數最多的條件放在最前面。

(8)儘量使用共享的SQL語句。如經常使用select * from dept where deptno=值。如果每一個‘值’都是常量,則每一次都會重新解釋,不能共享記憶體中的SQL語句優化結果。應把‘值’設定為一個變數,所有的共同語句都可以優化一次,高度共享語句解釋優化的結果。

示例:select * from dept where deptno=:d;

該條規範對應我們的SQL中的繫結變數的使用;

(9)使用優化線索機制進行訪問路徑控制。

示例:

selecte.ename

from emp e

where e.job||''='CLERK';

//不如下面的語句好:

select /*+FULL(EMP)*/ e.ename

from emp e

where e.job='CLERK';

(10)建議SQL統一採用StringBuffer來拼串;

示例:

              sqlBF.append(" select jgbh,jgmc,parent,isValid,note ");

              sqlBF.append("from sysgroup ");

              sqlBF.append("  where jgbh like ? ");

sqlBF.append("    and jgmc like ? ");

(11)查詢語句,要特別關注SQL查詢出的資料量,當明確查詢出的資料量比較大時,建議增加行數限制;

(12)減少對錶的查詢,在含有子查詢的SQL語句中,要特別注意減少對錶的查詢。

示例:

//一般情況下,效率較低。

select tab_name

from tables

wheretab_name = (select tab_name

  fromtab_columns

  where version = 604)

anddb_ver = (select db_ver

 fromtab_columns

  where version = 604);

//一般情況下,效率較高。

selecttab_name

from tables

where (tab_name, db_ver) = (select tab_name, db_ver

  fromtab_columns

  where version = 604);

3.索引使用原則

注:下文中的錯誤和正確只是說明是否能正確使用索引,並不是說明語句正確與否,特此說明。

(1)儘量避免對索引列進行計算

若對索引列進行了表示式計算,如加、減、乘、除等,索引會失效。

示例:

錯誤:where sal*1.1>950

正確:where sal>950/1.1

錯誤:where substr(name,1,7)=’CAPITAL’

正確:where name like ‘CAPITAL%’

(2)儘量注意比較值與索引列資料型別的一致性

當比較不同資料型別的資料時, ORACLE自動對列進行簡單的型別轉換。嚴禁使用隱式的型別轉換,必須顯示的寫出來。

示例:

emp_no為NUMBER型時

正確:where emp_no=123(推薦使用)

where emp_no=’123’(也可,不推薦使用)

emp_type為CHAR型時

錯誤:where emp_type=123 (此時,查詢時,不利用索引列)

正確:where emp_type=’123’

(3)儘量避免使用NULL

避免在索引列上使用IS NULL和IS NOT NULL,將用不到索引。

示例:

錯誤:where comm IS NOT NULL

錯誤:where comm IS NULL

正確:where comm>=0

(4)儘量避免使用NOT=(!=)

“!=”和“<>”因為自動加了NOT運算子,將不使用索引,避免使用。

示例:

錯誤:where deptno!=0

正確:where deptno>0

(5)對於複合索引,SQL語句必須使用主索引列

如果索引是建立在多個列上,只有在它的第一個列(leading column)被where子句引用時,優化器才會選擇使用該索引。

示例:

複合索引(deptno,job)

正確:where deptno=20 and job=’MANAGER’

正確:where deptno=20

正確:where job=’MANAGER’ and deptno=20

錯誤:where job=’MANAGER’

(6)ORDER BY子句

子句中,列的順序與索引列的順序一致;

子句中,列應為非空列。

(7)查詢列與索引列次序(WHERE)的一致性

示例:

selectempno,job

fromemp

whereempno<100

and job=’MANAGER’;

(8)避免索引列條件由萬用字元(%)開始

           索引列由萬用字元(%)開始時,索引失效。

示例:

where manager like ‘%HANMAN' 將進行全表掃描。

(9)避免相同的索引列互相比較

相同的索引列不能互相比較,這將會啟用全表掃描。

示例:

where account_name = nvl(:acc_name,account_name);

建議改寫為:

where account_name like nvl(:acc_name,'%');