oracle中sql語句的優化

1、執行順序及優化細則

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做爲基礎表,你會發現運行的速度會有很大的差距,
當基礎表放在後面,這樣的執行速度會明顯快不少。java

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

3. is null 和is not null
當要過濾列爲空數據或不爲空的數據時使用
select *
from student_info si --學生信息表
where si.school_id is null(當前列中的null爲少數時用is not null,不然is null)sql

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 * 來進行查詢,當你查詢使用*,
數據庫會進行解析並將*轉換爲所有列。oracle


2、替代優化
一、用>=替代> 
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
  執行時>=會比>執行得要快 
  
二、用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, 能夠把返回記錄最少的索引列寫在最前面
    
三、用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)
  執行會更有效率
    
四、 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要執行得快函數

五、分離表和索引 
老是將你的表和索引創建在另外的表空間內 
決不要將這些對象存放到SYSTEM表空間裏性能

3、一些優化技巧測試


一、計算表的記錄數時優化

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


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

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
)
執行速度是提升了,但可讀性反而差了..
因此這種寫法我的並不太推薦

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

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

五、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)
六、用錶鏈接代替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)

4、索引篇

一、運算致使的索引失效

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索引將失效*/ 
   
二、類型轉換致使的索引失效

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'
   
三、在索引列上進行計算引發的問題

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
將會獲得高效的運行速度

四、 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--索引有效 

五、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中全部的列必須定義爲非空. )
  
六、自動選擇索引
 
若是表中有兩個以上(包括兩個)索引,其中有一個惟一性索引,而其餘是非惟一性.
在這種狀況下,ORACLE將使用惟一性索引而徹底忽略非惟一性索引.

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

八、%致使的索引失效

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%'/*索引有效*/ 
以上只例子,具體仍是要針對各個不一樣的具體的業務使用

5、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條)

相關文章
相關標籤/搜索