1. 程式人生 > >oracle中sql語句的優化(轉帖)

oracle中sql語句的優化(轉帖)

本文轉載之http://www.cnblogs.com/netjxz/archive/2009/09/21/1570991.html

一、執行順序及優化細則

1.表名順序優化 
(1) 基礎表放下面,當兩表進行關聯時資料量少的表的表名放右邊
表或檢視: 
Student_info   (30000條資料)
Description_info (30條資料)  
select *
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'      
與    
select *
  from student_info     si--學生資訊表
      ,description_info di
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'   
以student_info作為基礎表,你會發現執行的速度會有很大的差距。
   
   
(2) 當出現多個表時,關聯表被稱之為交叉表,交叉表作為基礎表
select *
  from description_info di
    ,description_info di2
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and si.school_id = di.lookup_code(+)
   and di.lookup_type(+) = 'SCHOOL_ID'

select *
  from student_info     si--學生資訊表
      ,description_info di
      ,description_info di2
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and si.school_id = di.lookup_code(+)
   and di.lookup_type(+) = 'SCHOOL_ID'
以student_info作為基礎表,你會發現執行的速度會有很大的差距,
當基礎表放在後面,這樣的執行速度會明顯快很多。

2.where執行順序
where執行會從至下往上執行
select *
from student_info si --學生資訊表
where si.school_id=10 --學院ID
and  si.system_id=100--系ID
擺放where子句時,把能過濾大量資料的條件放在最下邊

3. is null 和is not null
當要過濾列為空資料或不為空的資料時使用
select *
from student_info si --學生資訊表
where si.school_id is null(當前列中的null為少數時用is not null,否則is null)

4.使用表別名
當查詢時出現多個表時,查詢時加上別名,
避免出現減少解析的時間欄位歧義引起的語法錯誤。

5. where執行速度比having快
儘可能的使用where代替having
select  from student_info si
group by si.student_id
having si.system_id!=100
  and si.school_id!=10
(select  from student_info si
wehre si.system_id!=100
and si.school_id!=10
group by si.student_id)  
  
6.  * 號引起的執行效率
儘量減少使用select * 來進行查詢,當你查詢使用*,
資料庫會進行解析並將*轉換為全部列。


二、替代優化
1、用>=替代>

 
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id>=10
  與
  select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id>9
  執行時>=會比>執行得要快 
  
2、用UNION替換OR (適用於索引列) 
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=10
  union 
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=2  
   上面語句可有效避免全表查詢
   select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=10 
  or ui.student_id=2
  如果堅持要用OR, 可以把返回記錄最少的索引列寫在最前面
    
3、用in 代替or
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=10
  or ui.student_id=20
  or ui.student_id=30
  改成
  select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id in (10,20,30)
  執行會更有效率
    
4、 Union All 與Union
Union All重複輸出兩個結果集合中相同記錄
如果兩個並集中資料都不一樣.那麼使用Union All 與Union是沒有區別的,
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=10
  union All
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=2  
  與
  select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=10
  union 
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id=2  
但Union All會比Union要執行得快

5、分離表和索引 
總是將你的表和索引建立在另外的表空間內 
決不要將這些物件存放到SYSTEM表空間裡

三、一些優化技巧


1、計算表的記錄數時

select count(si.student_id) 
from Student_info si(student_id為索引)

select count(*) from Student_info si
執行時.上面的語句明顯會比下面沒有用索引統計的語句要快

2.使用函式提高SQL執行速度

當出現複雜的查詢sql語名,可以考慮使用函式來提高速度
查詢學生資訊並查詢學生(李明)個人資訊與的數學成績排名
如 
select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.description = '李明'
   
而且我們將上面order_num排名寫成一個fuction時
create or replace package body order_num_pkg is
function order_num(p_student_id number) return_number is
  v_return_number number;
begin
  select res.order_num --排名
    into v_return_number
    from result res
   where res.student_id = di.student_id
   order by result_math;
  return v_return_number;
exception
  when others then
    null;
    return null;
end;
end order_num_pkg;
執行
select di.description student_name
      ,order_num_pkg.order_num(di.student_id) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.description = '李明'
執行查詢時的速度也會有所提高     
 
3.減少訪問資料庫的次數

執行次數的減少(當要查詢出student_id=100的學生和student_id=20的學生資訊時)
select address_id
from student_info si --學生資訊表
where si.student_id=100

select address_id
from student_info si --學生資訊表
where si.student_id=20
都進行查詢.這樣的效率是很低的
而進行
(
select si.address_id,si2.address_id
from student_info si --學生資訊表
,student_info si2 
where si.student_id=100
and si2.student_id=20 

select decode(si.student_id,100,address_id)
   ,decode(si.student_id,20,address_id)
from student_info si
)
執行速度是提高了,但可讀性反而差了..
所以這種寫法個人並不太推薦

4、用Exists(Not Exists)代替In(Not In)

   在執行當中使用Exists或者Not Exists可以高效的進行查詢

5、Exists取代Distinct取唯一值的

   取出關聯表部門對員工時,這時取出員工部門時,出現多條..
select distinct di.dept_name 
  from departments_info di --部門表
      ,user_info        ui --員工資訊表
where ui.dept_no = di.dept_no
   可以修改成
  select di.dept_name
    from departments_info di --部門表
   where  exists (select 'X'
            from user_info ui --員工資訊表
           where di.dept_no = ui.dept_no)
6、用表連線代替Exists
   通過表的關聯來代替exists會使執行更有效率
select ui.user_name
  from user_info ui--員工資訊表
where exists (select 'x '
          from departments_info di--部門表
         where di.dept_no = ui.dept_no
           and ui.dept_cat = 'IT');
執行是比較快,但還可以使用表的連線取得更快的查詢效率
   select ui.user_name
    from departments_info di
        ,user_info        ui --員工資訊表
   where ui.dept_no = di.dept_no
     and ui.department_type_code = 'IT'

程式碼是經測試並進行優化所寫,
以上只例子,具體使用還是要針對各個不同的具體的業務使用用Exists(Not Exists)代替In(Not In)

四、索引篇

1、運算導致的索引失效

select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and si.student_id+0=100/*student_id索引將失效*/ 
   
2、型別轉換導致的索引失效

select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.student_id='100'
  
student_id為number型別的索引,當執行下列語句,
oracle會自動轉換成
select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.student_id=to_number('100')
所幸,只是解析並轉換型別,並沒有導到失效,
但要是寫成下面,將會使用其失效
select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and to_char(di.student_id)='100'
   
3、在索引列上進行計算引起的問題

select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.student_id-2=10
在索引列中進行運算,將會不使用索引而使用全表掃描
而將
select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.student_id=10+2
將會得到高效的執行速度

4、 Is not null引起的問題(student_id為索引)

不要把存在空值的列做為索引,否則無法使用索引
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id is not null--索引失效 
  
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id>=-1--索引有效

5、Order by導致索引失效(student_id為索引)

select ui.user_name
  from user_info ui--員工資訊表
  group by ui.student_id   
而使用
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id>=-1
  將使其有效,
  在order by中只存在兩種條件下可以使用索引
  (ORDER BY中所有的列必須包含在相同的索引中並保持在索引中的排列順序
ORDER BY中所有的列必須定義為非空. )
  
6、自動選擇索引
 
如果表中有兩個以上(包括兩個)索引,其中有一個唯一性索引,而其他是非唯一性.
在這種情況下,ORACLE將使用唯一性索引而完全忽略非唯一性索引.

7、 !=導致索引失效
 
select ui.user_name
  from user_info ui--員工資訊表
  where ui.student_id!=0
在Where中使用!=將會把索引失效

8、%導致的索引失效

select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.look_code Like '%12'/*look_code為索引,索引將失效*/ 

select di.description student_name
      ,(select res.order_num--排名
         from result res
        where res.student_id = di.student_id
        order by result_math) order_num
  from description_info di
      ,student_info     si --學生資訊表
where si.student_id = di.lookup_code(+)
   and di.lookup_type(+) = 'STUDENT_ID'
   and di.look_code Like '12%'/*索引有效*/ 
以上只例子,具體還是要針對各個不同的具體的業務使用

五、oracle 中的not Exists與Not in的效能巨大差異

Not Exists與Not in的作用同樣是排除資料,在oracle 中使用not in並不象mysql中的執行那麼快,如(
select jt1.doc_num --單據號碼
      ,oalc.description school_name --學校名稱
      ,oalc2.description system_name --系名稱
      ,oalc.description class_name --班級名稱
  from java_table1            jt1
      ,java_table_description oalc
      ,java_table_description oalc2
      ,java_table_description oalc3
where oalc.lookup_type(+) = 'JAVA_SCHOOL_NAME'
   and jt1.school_id = oalc.lookup_code(+)
   and oalc2.lookup_type(+) = 'JAVA_SYSTEM_NAME'
   and jt1.system_id = oalc2.lookup_code(+)
   and oalc3.lookup_type(+) = 'JAVA_CLASS_NAME'
   and jt1.class_id = oalc3.lookup_code(+)
   and not exists
(select jt2.header_id
          from java_table2 jt2 jt1.header_id = jt2.header_id))

select jt1.doc_num --單據號碼
      ,oalc.description school_name --學校名稱
      ,oalc2.description system_name --系名稱
      ,oalc.description class_name --班級名稱
  from java_table1            jt1
      ,java_table_description oalc
      ,java_table_description oalc2
      ,java_table_description oalc3
where oalc.lookup_type(+) = 'JAVA_SCHOOL_NAME'
   and jt1.school_id = oalc.lookup_code(+)
   and oalc2.lookup_type(+) = 'JAVA_SYSTEM_NAME'
   and jt1.system_id = oalc2.lookup_code(+)
   and oalc3.lookup_type(+) = 'JAVA_CLASS_NAME'
   and jt1.class_id = oalc3.lookup_code(+)
   and jt1.header_id not in (select jt2.header_id from java_table2 jt2)

當jt2表中的資料比較大時,就會出現巨大的差異,以上只能是我的個人理解與測試結果(java_table1 檢視測試

資料量為36749,java_table2 為300條),如有其它可相互討論

相關推薦

oraclesql語句優化()

本文轉載之http://www.cnblogs.com/netjxz/archive/2009/09/21/1570991.html一、執行順序及優化細則1.表名順序優化 (1) 基礎表放下面,當兩表進行關聯時資料量少的表的表名放右邊表或檢視: Student_info  

Oracle sql語句的取前n條數據

沒有 blog tab 註意 sql table bsp num 數據 取得薪水最高的前五名員工 sql: select * from ( select empno,ename,sal from emp order by sal desc) where rownum&l

oraclesql語句多個查詢結果的交集、差集和並集

1.交集 intersect運算:返回查詢結果中相同的部分。 SELECT product_id FROM tab1 INTERSECT SELECT product_

ORACLELIKE語句優化

  1。儘量不要使用 like '%%'     2。對於 like '%' (不以 % 開頭),Oracle可以應用 colunm上的index 3。對於 like '%…' 的 (不以 % 結尾),可以利用reverse + function index 的形式,變化成

ORACLEsql語句----運算子的優先順序

算數運算子——>連線運算子——>比較(關係)運算子——>IS NULL , IS NOT NULL , LIKE , NOT LIKE , IN , NOT IN ——>BETWEEN , NOT BETWEEN ——>NOT 邏輯運算子——&g

oracle取時間戳日期格式的SQL語句

SELECT TO_CHAR(ADDTIME/ (60 * 60 * 24) + TO_DATE('1970-01-01 08:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') AS TESTDATE  FR

oraclehint的使用-SQL語句優化

表明對語句塊選擇基於開銷的優化方法,並獲得最佳吞吐量,使資源消耗最小化. 例如: SELECT /*+ALL+_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT'; 2. /*+FIRST_ROWS*/ 表明對語句塊選擇基於開銷的優化方

[]Oracle的update語句優化研究

lis 錯誤 wid class 插入 集合 top 執行 gin 原文地址:http://blog.csdn.net/u011721927/article/details/39228001 一、 update語句的語法與原理 1. 語法 單表:

SQL語句優化系列四(Oracle數據庫日期格式轉換)

fun ont 如果 etime 當前時間 字符轉換函數 dual minute nbsp Oracle數據庫日期格式轉換 select sysdate from dual select to_char(sysdate,‘yyyy/mm/dd hh24:mi:ss‘) as

數據庫性能優化SQL語句優化 java知音)

可能 資源 詳細介紹 有助於 效果 這就是 詳細 分組統計 完全 一、問題的提出 在應用系統開發初期,由於開發數據庫數據比較少,對於查詢SQL語句,復雜視圖的編寫等體會不出SQL語句各種寫法的性能優劣,但是如果將應用系統提交實際應用後,隨著數據庫中數據的增加,系統的

在外部應用執行oraclesql語句時出現“不支援的列資料型別”錯誤

如  SELECT OBJECTID,osmid,username,userid,versional,lat,lon,visible,changeset,timestamps,issimple,fc,dsg,code,gbcode,gbdes,tags,bz,names,n

資料庫效能之SQL語句優化

百萬級資料優化 一.I_IPTVLOGIN00 (五十萬),TEMP_STBINFO (五百萬) 1.select a.loginAccount,a.stbID,b.DEV_SNO from I_IPTVLOGIN00 a,TEMP_STBINFO b where a.s

oraclesql語句的簡單優化

執行路徑: ORACLE的這個功能大大地提高了SQL的執行效能並節省了記憶體的使用: 我們發現,單表資料的統計比多表統計的速度完全是兩個概念.單表統計可能只要0.02秒,但是2張表聯合統計就可能要幾 十表了. 這是因為ORACLE只對簡單的表提供高速緩衝(cache buffering)

oracle 編寫sql語句獲取表的最後一條資料

select p.* from (select * from t_cfg_menu t order by t.menu_id desc) p where rownum = 1 首先查詢表中資料按降序排列,然後通過“rownum = 1”獲取第一條資料,即是原

mysql和oracle的xml的sql語句

<select id="query" resultMap="resultMap">select * from role  <where><if test="roleName != null and roleName != ''">and ROLE_NAME like '%'

Oracle 建立索引及利用索引的SQL語句優化

資料庫索引: 索引有單列索引 複合索引之說 如何某表的某個欄位有主鍵約束和唯一性約束,則Oracle 則會自動在相應的約束列上建議唯一索引。資料庫索引主要進行提高訪問速度。 建設原則:  1、索引應該經常建在Where 子句經常用到的列上。如果某個大表經常使用某個欄位進行

ORACLESQL語句簡單應用(四)(11g)

union times truncate sql語句 默認值 位數 lib rownum dual 排序 後加 nulls last 在降序排列中把null放在最後 select to_char(sysdate,‘q‘) from dual; dual

ORACLESQL語句簡單應用(五)(11g)

應用 11g sql cal foreign ora 每次 int pri not null 非空 字段+not null unique 唯一 primary key 主鍵(確保數據不能重復) foreign key 外鍵 check 必須

Oracle MERGE語句的用法(轉載)

同時 sdn ble reat nth merge type href detail 原文章出處(http://blog.csdn.net/lichkui/article/details/4306299) MERGE語句是Oracle9i新增的語法,用來合並UPDATE和I

Oraclesql語句的兩種判斷形式

紅色 其他 num cor score ask rac res 復雜 Oracle的sql語句的兩種判斷形式 判斷當前列同時改動當前列 判斷一個情況改動其他值 一類情況詳解:實現的是當num這一列的值為3時,就顯示好 以此類推 1)case num when