sql優化技巧

1、        關於索引的知識sql

要寫出運行效率高的sql,須要對索引的機制有必定了解,下面對索引的基本知識作一介紹。編輯器

一、        索引的優勢和侷限
索引能夠提升查詢的效率,但會下降dml操做的效率。
因此創建索引時須要權衡。對於dml操做比較頻繁的表,索引的個數不宜太多。工具

二、        什麼樣的列須要建索引?
常常用於查詢、排序和分組的列(即常常在where、order或group by子句中出現的列)。code

三、        主鍵索引和複合索引
對於一張表的主鍵,系統會自動爲其創建索引。
若是一張表的幾列常常同時做爲查詢條件,可爲其創建複合索引。排序

四、        創建索引的語句
create  index  i_staff  on  staff  (empno);
create  index  i_agent  on  agent  (empno, start_date);索引

五、        刪除索引的語句
drop  index  I_staff;
drop  index  I_agent;開發

六、        查詢索引的語句
法一:利用數據字典
表一:all_indexes  查看一張表有哪些索引以及索引狀態是否有效
主要字段: index_name,  table_name,  status
例如:select   index_name,  status  
from  all_indexes
        where  table_name=’STAFF_INFO’;
      INDEX_NAME        STATUS
      ---------------------       -----------
      I_STAFF             VALID  
            表二:all_ind_columns  查看一張表在哪些字段上建了索引
              主要字段: table_name,  index_name,  column_name,  column_position
例如: select  index_name,  column_name,  column_position
from  all_ind_columns
         where  table_name=’AGENT’
      INDEX_NAME        COLUMN_NAME     COLUMN_POSITON
      ---------------------       -----------------------      --------------------------
     I_AGENT             EMPNO              1
     I_AGENT             START_DATE         2
因而可知,agent表中有一個複合索引(empno, start_date )
     法二:利用toad工具
toad用戶界面比sql*plus友好,而且功能強大。你能夠在toad編輯器中鍵入表名,按F4,即可見到這張表的表結構以及全部索引列等基本信息。rem

七、        索引的一些特色
1): 不一樣值較多的列上可創建檢索,不一樣值少的列上則不要建。好比在僱員表的「性別」列上只有「男」與「女」兩個不一樣值,所以就不必創建索引。若是創建索引不但不會提升查詢效率,反而會嚴重下降更新速度。
2): 若是在索引列上加表達式,則索引不能正常使用
   例如:b1,c1分別是表b,c的索引列
select  *  from  b  where  b1/30< 1000 ;
select  *  from  c  where  to_char(c1,’YYYYMMDD HH24:MI:SS’) = ‘200203 14:01:01’;
以上都是不正確的寫法
        3): where子句中若是使用in、or、like、!=,均會致使索引不能正常使用
           例如:select  *  from  b  where  b1=30  or  b1=40;
      4): 使用複合索引進行查詢時必須使用前置列
         例如表a上有一個複合索引(c1,c2,c3),則c1爲其前置列
         若是用c1或c1+c2或c1+c2+c3爲條件進行查詢,則該複合索引能夠發揮做用,反之,用c2或c3或c2+c3進行查詢,則該索引不能起做用。it


二. 書寫sql注意事項:io

一、        避免給sql語句中引用的索引列添加表達式:
典型實例:
b1,c1分別是表b,c的索引列:
1)        select  *  from  b  where  b1/30< 1000 ;
2)        select  *  from  c  where to_char(c1,’YYYYMMDD HH24:MI:SS’) = ‘200203 14:01:01’;
替代方案:
1)        select  *  from  b where  b1 < 30000;
2)        select * from c  where c1 = to_date(‘20020301 14:01:01’, ‘YYYYMMDD HH24:MI:SS’);
注:在lbs中有兩個重要字段,pol_info中的undwrt_date和prem_info中的payment_date,這兩個日期是帶時分秒的,因此常常有同事用to_char 來查詢某一時間段的數據。
例如:select  count(*)  from  pol_info  where  to_char(undwrt_date,’YYYYMMDD’)=’20020416’;
      select  count(*)  from  prem_info  where  to_char(undwrt_date,’YYYYMM’)=’200203’;
替代方案:
select  count(*)  from  pol_info  
where  undwrt_date>=to_date(’20020416’,’YYYYMMDD’)  and
           undwrt_date<to_date(’20020417’,’YYYYMMDD’);
select  count(*)  from  prem_info  
where  payment_date>=to_date(’20020301’,’YYYYMMDD’)  and
         payment_date<to_date(’20020401’,’YYYYMMDD’);

二、        避免在where子句中使用in、or、like、!=
典型實例:
a1是a表上的索引列:
1) select  *  from  a
   where  ( a1 = ‘0’ and ...)  or  (a1 = ‘1’ and ...);
2) select  count(*)  from  a  where  a1  in  (‘0’,’1’) ;
替代方案:
1)        select  *  from  a  where  a1 = ‘0’  and ...
union
select  *  from  a  where  a1 = ‘1’  and ...
2) select  count(*)  from  a  where  a1 = ‘0’;
  select  count(*)  from  a  where a1 = ‘1’;
   而後作一次加法運算;或者直接用存儲過程來實現;
小結:
對字段使用了 ‘in,or,like’ 作條件、對字段使用了不等號 ‘!=’,均會使索引失效;若是不產生大量重複值,能夠考慮把子句拆開;拆開的子句中應該包含索引,或者使用union連結符代替。另外一種方式是使用存儲過程,它使SQL變得更加靈活和高效。

三、        創建適當的索引
曾經接過開發的一個統計sql, select …  from  tablea  where  cola=…  and  …
運行效率很是慢,經查tablea數據量巨大,再查all_ind_columns,發現cola是tablea的一個複合索引中的一列,但不是前置列。象這種狀況,就須要與開發商量,是否針對cola建一個索引。

四、        like和substr
對於‘like’和‘substr’,其效率並無多大分別。可是,當所搜索的值不存在時,使用‘like’的速度明顯大於‘substr’。
因此:select  *  from  a  where  substr(a1,1,4) = '5378'  能夠用like替代
select  *  from  a  where  a1  like  ‘5378%’;

五、 寫where條件時,有索引字段的判斷在前,其它字段的判斷在後;若是where條件中用到複合索引,按照索引列在複合索引中出現的順序來依次寫where條件;

六、使用多表鏈接時,在from子句中,將記錄數少的表放在後面,可提升執行效率;

七、避免使用not in 
not  in 是效率極低的寫法,儘可能使用minus或外鏈接加以替代
典型實例:
1) select col1 from tab1 where col1 not in (select col1 from tab2);
2) select sum(col2) from tab1 where col1 not in (select col1 from tab2);
替代方案
select col1 from tab1 minus  select col1 from tab2;
    select  sum(a.col2)  from  tab1 a, tab2  b 
where a.col1=b.col2(+) and b.col1 is null;

八、多表查詢時,若是其中一個表的記錄數量明顯大於其餘表,則能夠先對此表進行查詢後,再與其餘小表進行錶鏈接。
典型實例:
select  a.plan_code,  b.dno,  c,tno,  sum(a.tot_modal_prem),
from  prem_info a,  dept_ref b,  plan_type c
where  substr(a.deptno,1,7) = substr(b.deptno,1,7)
and a.plan_code = c.plan_code
group by b.dno,  c.tno,  a.plan_code;
替代方案:
select  b.dno,  c.tno,  a.plan_code,  a.tot_amount
from  (select  plan_code,  deptno,  sum(tot_modal_prem)  tot_amount
from  prem_info
group  by  deptno,  plan_code) a
dept_ref  b,
plan_type  c
  where  substr(a.deptno,1,7) = substr(b.deptno,1,7)
       and  a.plan_code = c.plan_code
group  by  b.dno,  c.tno,  a.plan_code;
小結:
因爲prem_info表的記錄數遠遠大於dept_ref表和plan_type表中的記錄數, 因此首先從prem_info表中查詢須要的記錄,此時記錄數已經被大量縮小,而後再和其餘兩個錶鏈接,速度會獲得很大改善!

九、查詢數量較大時,使用錶鏈接代替IN,EXISTS,NOT IN,NOT EXISTS等。典型實例:a、使用IN:select sum(col2) from tab1 where col1 in (select col1 from tab2);使用EXISTS::select sum(col2) from tab1 a where exists ( select * from tab2 where col1=a.col1);b、使用NOT IN:select sum(col2) from tab1 where col1 not in (select col1 from tab2);使用NOT EXISTS:select sum(col2) from tab1 a where not exists ( select * from tab2 where col1=a.col1);          替代方案:a、使用鏈接:select sum(a.col2) from tab1 a,tab2 b where a.col1=b.col2;b、使用外鏈接:select sum(a.col2) from tab1 a,tab2 b where a.col1=b.col2(+) and b.col1 is null; 

相關文章
相關標籤/搜索