高效能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,'%');