1. 程式人生 > >資料庫SQL優化——使用EXIST代替IN

資料庫SQL優化——使用EXIST代替IN

  1. 查詢進行優化,應儘量避免全表掃描
    對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引

    . 嘗試下面的技巧以避免優化器錯選了表掃描:

    · 使用ANALYZE TABLEtbl_name為掃描的表更新關鍵字分佈。

    · 對掃描的表使用FORCEINDEX告知MySQL,相對於使用給定的索引表掃描將非常耗時。

        SELECT * FROM t1, t2 FORCE INDEX (index_for_column)   WHERE t1.col_name=t2.col_name;
    

    · 用–max-seeks-for-key=1000選項啟動mysqld或使用SET max_seeks_for_key=1000告知優化器假設關鍵字掃描不會超過1,000次關鍵字搜尋。

    1). 應儘量避免在 where 子句中對欄位進行 null 值判斷

    否則將導致引擎放棄使用索引而進行全表掃描,如:
    
    select id from t where num is null
    
    NULL對於大多數資料庫都需要特殊處理,MySQL也不例外,它需要更多的程式碼,更多的檢查和特殊的索引邏輯,有些開發人員完全沒有意識到,建立表時NULL是預設值,但大多數時候應該使用NOT NULL,或者使用一個特殊的值,如0,-1作為默  認值。
    
    不能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列這樣的情況下,只要這些列中有一列含有null,該列    就會從索引中排除。也就是說如果某列存在空值,即使對該列建索引也不會提高效能。 任何在where子句中使用is null或is not null的語句優化器是不允許使用索引的。
    
    此例可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:
    
     select id    from t where num=0
    

    2). 應儘量避免在 where 子句中使用!=或<>操作符

     否則將引擎放棄使用索引而進行全表掃描。
     MySQL只有對以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE。 
    
     可以在LIKE操作中使用索引的情形是指另一個運算元不是以萬用字元(%或者_)開頭的情形。例如:
     SELECT id FROM  t WHERE col LIKE 'Mich%'; #  這個查詢將使用索引,
     SELECT id FROM  t WHERE col  LIKE '%ike';   #這個查詢不會使用索引。
    

    3). 應儘量避免在 where 子句中使用 or 來連線條件

    否則將導致引擎放棄使用索引而進行全表掃描,如:
    
    select id from t where num=10 or num=20
    
    可以 使用UNION合併查詢: select id from t where num=10 union all select id from t where num=20
    

    在某些情況下,or條件可以避免全表掃描的。

    1 .where 語句裡面如果帶有or條件, myisam表能用到索引, innodb不行。
    
       2 .必須所有的or條件都必須是獨立索引
    

    mysql or條件可以使用索引而避免全表

    4) .in 和 not in 也要慎用,否則會導致全表掃描,

    如:
    
    select id from t where num in(1,2,3)
    
    對於連續的數值,能用 between 就不要用 in 了:
    
    Select id from t where num between 1 and 3
    

    5).下面的查詢也將導致全表掃描:

    select id from t where name like '%abc%' 或者
    
    select id from t where name like '%abc' 或者
    
    若要提高效率,可以考慮全文檢索。
    
    而select id from t where name like 'abc%' 才用到索引
    

    7). 如果在 where 子句中使用引數,也會導致全表掃描。

    因為SQL只有在執行時才會解析區域性變數,但優化程式不能將訪問計劃的選擇推 遲到執行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

    select id from t where [email protected]

    可以改為強制查詢使用索引: select id from t with(index(索引名)) where [email protected]

    8). 應儘量避免在 where 子句中對欄位進行表示式操作,

    這將導致引擎放棄使用索引而進行全表掃描。如:

    select id from t where num/2=100

    應改為: select id from t where num=100*2

9). 應儘量避免在where子句中對欄位進行函式操作,

   這將導致引擎放棄使用索引而進行全表掃描。如:

  select id from t where substring(name,1,3)='abc'   --name

  select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’ 

  生成的id 應改為:

  select id from t where name like 'abc%'

  select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

10).不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,

  否則系統將可能無法正確使用索引。

11). 索引欄位不是複合索引的字首索引

   例如 在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓欄位順序與索引順序相一致。

2 .其他一些注意優化:
12). 不要寫一些沒有意義的查詢,

    如需要生成一個空表結構:

    select col1,col2 into #t from t where 1=0

    這類程式碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣: create table #t(...)

13). 很多時候用 exists 代替 in 是一個好的選擇:

   select num from a where num in(select num from b)

   用下面的語句替換:

   select num from a where exists(select 1 from b where num=a.num)

14). 並不是所有索引對查詢都有效,

   SQL是根據表中資料來進行查詢優化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

15). 索引並不是越多越好,

   索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

16).應儘可能的避免更新 clustered 索引資料列,

   因為 clustered 索引資料列的順序就是表記錄的物理儲存順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。

17).儘量使用數字型欄位,

  若只含數值資訊的欄位儘量不要設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。這是因為引擎在處理查詢和連線時會逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。

18).儘可能的使用 varchar/nvarchar 代替 char/nchar ,

  因為首先變長欄位儲存空間小,可以節省儲存空間,其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。

19).最好不要使用”“返回所有: select from t ,

 用具體的欄位列表代替“*”,不要返回用不到的任何欄位。
  1. 臨時表的問題:
    20). 儘量使用表變數來代替臨時表。

    如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。

21).避免頻繁建立和刪除臨時表,以減少系統表資源的消耗。

22).臨時表並不是不可使用,

 適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,最好使用匯出表。

23).在新建臨時表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;

 如果資料量不大,為了緩和系統表的資源,應先create table,然後insert。

24). 如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

  1. 遊標的問題:
    25).儘量避免使用遊標,

    因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。

26).使用基於遊標的方法或臨時表方法之前,

  應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

27).與臨時表一樣,遊標並不是不可使用。

 對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

28).在所有的儲存過程和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。

  無需在執行儲存過程和觸發器的每個語句後向客戶端傳送 DONE_IN_PROC 訊息。
  1. 事務的問題:
    29).儘量避免大事務操作,提高系統併發能力。

  2. 資料量的問題
    30).儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。

  3. COUNT優化:
    31) count(*) 優於count(1)和count(primary_key)

      很多人為了統計記錄條數,就使用 count(1) 和 count(primary_key) 而不是 count() ,他們認為這樣效能更好,其實這是一個誤區。對於有些場景,這樣做可能效能會更差,應為資料庫對 count() 計數操作做了一些特別的優化。
    32)count(column) 和 count(*) 是不一樣的

      這個誤區甚至在很多的資深工程師或者是 DBA 中都普遍存在,很多人都會認為這是理所當然的。實際上,count(column) 和 count(*) 是一個完全不一樣的操作,所代表的意義也完全不一樣。
      count(column) 是表示結果集中有多少個column欄位不為空的記錄
      count(*) 是表示整個結果集有多少條記錄

1)innodb引擎在統計方面和myisam是不同的,Myisam內建了一個計數器,

Count()在沒有查詢條件的情況下使用 select count() from table 的時候,Myisam直接可以從計數器中取出資料。而innodb必須全表掃描一次方能得到總的數量

  1. 但是當有查詢條件的時候,兩者的查詢效率一致。

  2. 主鍵索引count(*)的時候之所以慢

InnoDB引擎:

[1] 資料檔案和索引檔案儲存在一個檔案中,主鍵索引預設直接指向資料儲存位置。

[2] 二級索引儲存指定欄位的索引,實際的指向位置是主鍵索引。當我們通過二級索引統計資料的時候,無需掃描資料檔案;而通過主鍵索引統計資料時,由於主鍵索引與資料檔案存放在一起,所以每次都會掃描資料檔案,所以主鍵索引統計沒有二級索引效率高。

[3] 由於主鍵索引直接指向實際資料,所以當我們通過主鍵id查詢資料時要比通過二級索引查詢資料要快。

l MyAsm引擎

[1] 該引擎把每個表都分為幾部分儲存,比如使用者表,包含user.frm,user.MYD和user.MYI。

[2] User.frm負責儲存表結構

[3] User.MYD負責儲存實際的資料記錄,所有的使用者記錄都儲存在這個檔案中

[4] User.MYI負責儲存使用者表的所有索引,這裡也包括主鍵索引。

  1. 優化order by語句
    基於索引的排序
    MySQL的弱點之一是它的排序。雖然MySQL可以在1秒中查詢大約15,000條記錄,但由於MySQL在查詢時最多隻能使用一個索引。因此,如果WHERE條件已經佔用了索引,那麼在排序中就不使用索引了,這將大大降低查詢的速度。我們可以看看如下的SQL語句:
    SELECT * FROM SALES WHERE NAME = “name” ORDER BY SALE_DATE DESC;
    在以上的SQL的WHERE子句中已經使用了NAME欄位上的索引,因此,在對SALE_DATE進行排序時將不再使用索引。為了解決這個問題,我們可以對SALES表建立複合索引:
    ALTER TABLE SALES DROP INDEX NAME, ADD INDEX (NAME,SALE_DATE)
    這樣再使用上述的SELECT語句進行查詢時速度就會大副提升。但要注意,在使用這個方法時,要確保WHERE子句中沒有排序欄位,在上例中就是不能用SALE_DATE進行查詢,否則雖然排序快了,但是SALE_DATE欄位上沒有單獨的索引,因此查詢又會慢下來。

    在某些情況中, MySQL可以使用一個索引來滿足 ORDER BY子句,而不需要額外的排序。 where條件和order by使用相同的索引,並且order by 的順序和索引順序相 同,並且order by的欄位都是升序或者都是降序。例如:下列sql可以使用索引。
    SELECT * FROM t1 ORDER BY key_part1,key_part2,… ;
    SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;
    SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
    但是以下情況不使用索引:
    SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC ; –order by 的欄位混合 ASC 和 DESC
    SELECT * FROM t1 WHERE key2=constant ORDER BY key1 ;– 用於查詢行的關鍵字與 ORDER BY 中所使用的不相同
    SELECT * FROM t1 ORDER BY key1, key2 ;– 對不同的關鍵字使用 ORDER BY :

  2. 優化GROUP BY
    預設情況下, MySQL 排序所有 GROUP BY col1 , col2 , …. 。查詢的方法如同在查詢中指定 ORDER BY col1 , col2 , … 。如果顯式包括一個包含相同的列的 ORDER BY
    子句, MySQL 可以毫不減速地對它進行優化,儘管仍然進行排序。如果查詢包括 GROUP BY 但你想要避免排序結果的消耗,你可以指定 ORDER BY NULL禁止排序。
    例如 :
    INSERT INTO foo SELECT a, COUNT(*) FROM bar GROUP BY a ORDER BY NULL;

  3. 優化 OR
    1 .where 語句裡面如果帶有or條件, myisam表能用到索引, innodb不行。

相關推薦

資料庫SQL優化——使用EXIST代替IN

查詢進行優化,應儘量避免全表掃描 對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引 . 嘗試下面的技巧以避免優化器錯選了表掃描: · 使用ANALYZE TABLEtbl_name為掃描的表

資料庫SQL優化大總結之 百萬級資料庫面試優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。   一、百萬級資料庫優化

華為面試題之資料庫sql優化方案

對於資料庫分割槽欄位,索引欄位,基本資料型別如何在sql進行優化查詢 答案:我們應該在過濾條件使用順序調整成分割槽條件/索引條件/基本資料型別條件 資料庫分割槽 是一種物理資料庫設計技術,DBA和資料庫建模人員對其相當熟悉。雖然分割槽技術可以實現很多效果,但其主要目的是

資料庫SQL優化大總結之 百萬級資料庫優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。 1.對查詢進行

資料庫sql優化的幾種方法總結

在sql查詢中為了提高查詢效率,我們常常會採取一些措施對查詢語句進行sql優化,下面總結的一些方法,有需要的可以參考參考。 1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 wher

資料庫SQL優化大總結之百萬級資料庫優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。 1.對查詢進行優化

資料庫SQL優化

SQL優化   我們要做到不但會寫 SQL,還要做到寫出效能優良的 SQL。SQL優化需要注意及遵循的準則很多,本文只列舉核心部分:  1) 儘量少用IN操作符,基本上所有的IN操作符都可以用EXISTS代替。   2) 不用NOT IN操作符,可以用NOT EXISTS

ORACLE 資料庫 SQL 優化

出處: 1.資料庫訪問優化法則 要正確的優化SQL,我們需要快速定位能性的瓶頸點,也就是說快速找到我們SQL主要的開銷在哪裡?而大多數情況效能最慢的裝置會是瓶頸點,如下載時網路速度可能會是瓶頸點,本地複製檔案時硬碟可能會是瓶頸點,為什麼這些一般的工

資料庫 SQL優化和觸發器

常見的SQL優化 SQL語句巢狀一般不超過三層,SQL語句不能寫得過長,過於冗餘且容易出錯。 臨時表:使用臨時表加快查詢和索引的效率。 巧妙使用OR或者AND:數量相差過大的情況下則可以分開執行語句。 只在必要情況下使用begin tran:begin tran 標記事務

資料庫SQL優化總結

1.對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如: select id from t where n

讓天下沒有難用的資料庫 » SQL優化的一些總結

SQL的優化是DBA日常工作中不可缺少的一部分,記得在學生時期,曾經在ITPUB上看到一篇帖子,當時樓主在介紹SQL優化的時候,用一個公式來講解他在做sql優化的時候遵循的原則:           T=S/V(T代表時間,S代表路程,V代表速度) S指SQL所需訪問的資源總量,V指SQL單位時間所

資料庫SQL優化大總結1之- 百萬級資料庫優化方案

一、百萬級資料庫優化方案1.對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t

資料庫sql優化總結之1-百萬級資料庫優化方案+案例分析

專案背景 有三張百萬級資料表 知識點表(ex_subject_point)9,316條資料 試題表(ex_question_junior)2,159,519條資料 有45個欄位 知識點試題關係表(ex_question_r_knowledge)3,156,155條資料

資料庫sql優化總結之2-百萬級資料庫優化方案+案例分析

專案背景有三張百萬級資料表知識點表(ex_subject_point)9,316條資料試題表(ex_question_junior)2,159,519條資料 有45個欄位知識點試題關係表(ex_question_r_knowledge)3,156,155條資料測試資料庫為:m

MySQL資料庫SQL優化第四篇:通過trace分析優化器如何選擇執行計劃

 MySQL5.6提供了對SQL的跟蹤trace,通過trace檔案能夠進一步瞭解為什麼優化器選擇A執行計劃而不是選擇B執行計劃,幫助我們更好地理解優化器行為。     使用方式:首先開啟trace,設定格式為JSON,設定trace最大能夠使用的記憶體大小,避免解析過程中

ORACLE資料庫SQL優化--->如何執行計劃的執行順序

建議安裝(10g即以上版本上)xplan package,XPALN包其實是對DBMS_XPLAN包的封裝,使用XPLAN包就可以很清晰的看到執行計劃的執行順序。 安裝很簡單:其中xplan.sql_.txt可以到如下的網站下載: [[email protec

ORACLE資料庫SQL優化--->如何得到真實的執行計劃

在ORACLE資料庫裡通常可以使用如下的四種方法來得到目標SQL的執行計劃: 1,EXPLAIN PLAN命令 2,DBMS_XPLAN包 3,SQLPLUS中的AUTOTRACE開關 4,10046事件 除了第四種方法外,其他的三種方法得到的執行計劃都有可能不準確。在OR

資料庫sql優化規則

1. 選擇最有效率的表名順序  按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最後的表(基礎表 driving table)將被最先處理. 在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎表.當DB2處理多個表時,會運用排序及合併的

宜信-運維-資料庫|SQL優化:一篇文章說清楚Oracle Hint的正確使用姿勢

一、提示(Hint)概述 1、為什麼引入Hint? Hint是Oracle資料庫中很有特色的一個功能,是很多DBA優化中經常採用的

SQL優化--使用 EXISTS 代替 IN 和 inner join來選擇正確的執行計劃

tool pos inner ner 使用 邏輯讀 rda jpg 分享 在使用Exists時,如果能正確使用,有時會提高查詢速度: 1,使用Exists代替inner join 2,使用Exists代替 in 1,