SQL優化- 數據庫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 num=@num

可以改為強制查詢使用索引: select id from t with(index(索引名)) where num=@num

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 ,

 用具體的字段列表代替“*”,不要返回用不到的任何字段。

臨時表的問題: 
20). 盡量使用表變量來代替臨時表。

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

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

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

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

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

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

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

游標的問題: 
25).盡量避免使用游標,

因為游標的效率較差,如果游標操作的數據超過1萬行,那么就應該考慮改寫。

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

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

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

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

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

  無需在執行存儲過程和觸發器的每個語句后向客戶端發送 DONE_IN_PROC 消息。

事務的問題: 
29).盡量避免大事務操作,提高系統並發能力。
數據量的問題 
30).盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
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(*)的時候之所以慢

    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不行。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM