SQL優化匯總


今天面某家公司,然后問我SQL優化,感覺有點忘了,今天特此總結一下:

 總結得是分兩方面:索引優化和查詢優化;

 

 

一. 索引優化:

1. 獨立的列

在進行查詢時,索引列不能是表達式的一部分,也不能是函數的參數,否則無法使用索引。

例如下面的查詢不能使用 actor_id 列的索引:

#這是錯誤的
SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

 優化方式:可以將表達式、函數操作移動到等號右側。如下:

SELECT actor_id FROM sakila.actor WHERE actor_id  = 5 - 1;

 

 

2. 多列索引

在需要使用多個列作為條件進行查詢時,使用多列索引比使用多個單列索引性能更好。

例如下面的語句中,最好把actor_id 和 film_id 設置為多列索引。猿輔導有道題,詳見鏈接,可以讓理解更深刻。

SELECT film_id, actor_ id FROM sakila.film_actor
WHERE actor_id = 1 AND film_id = 1;

 

3. 索引列的順序

讓選擇性最強的索引列放在前面。MySql最左前綴原則

索引的選擇性是指:不重復的索引值和記錄總數的比值。最大值為 1,此時每個記錄都有唯一的索引與其對應。選擇性越高,每個記錄的區分度越高,查詢效率也越高。

例如下面顯示的結果中 customer_id 的選擇性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。

SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,
COUNT(*)
FROM payment;

#結果如下
staff_id_selectivity: 0.0001
customer_id_selectivity: 0.0373
COUNT(*): 16049

 

4. 前綴索引

對於 BLOB、TEXT 和 VARCHAR 類型的列,必須使用前綴索引,只索引開始的部分字符。

前綴長度的選取需要根據索引選擇性來確定。

 

5. 覆蓋索引

索引包含所有需要查詢的字段的值。具有以下優點:

  • 索引通常遠小於數據行的大小,只讀取索引能大大減少數據訪問量。

  • 一些存儲引擎(例如 MyISAM)在內存中只緩存索引,而數據依賴於操作系統來緩存。因此,只訪問索引可以不使用系統調用(通常比較費時)。

  • 對於 InnoDB 引擎,若輔助索引能夠覆蓋查詢,則無需訪問主索引。

 

以下為優先使用索引,避免全表掃描:

6. mysql在使用like進行模糊查詢的時候把%放后面,避免開頭模糊查詢

因為mysql在使用like查詢的時候只有使用后面的%時,才會使用到索引。

如:'%ptd_' 和 '%ptd_%' 都沒有用到索引;而 'ptd_%' 使用了索引。

#進行全表查詢,沒有用到索引
EXPLAIN SELECT * FROM `user` WHERE username LIKE '%ptd_%';
EXPLAIN SELECT * FROM `user` WHERE username LIKE '%ptd_';

#有用到索引
EXPLAIN SELECT * FROM `user` WHERE username LIKE 'ptd_%';

 再比如:經常用到的查詢數據庫中姓張的所有人:

SELECT * FROM `user` WHERE username LIKE '張%';

 

 

7. 在表中建立索引,優先考慮where、group by使用到的字段

 

8. 盡量避免使用in 和not in,會導致數據庫引擎放棄索引進行全表掃描。

比如:

SELECT * FROM t WHERE id IN (2,3)

SELECT * FROM t1 WHERE username IN (SELECT username FROM t2)

優化方式:如果是連續數值,可以用between代替。如下:

SELECT * FROM t WHERE id BETWEEN 2 AND 3

如果是子查詢,可以用exists代替。如下:

SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.username = t2.username)

 

9. 盡量避免使用or,會導致數據庫引擎放棄索引進行全表掃描

如:

SELECT * FROM t WHERE id = 1 OR id = 3

優化方式:可以用union代替or。如下:

SELECT * FROM t WHERE id = 1
UNION
SELECT * FROM t WHERE id = 3

 

10. 盡量避免進行null值的判斷,會導致數據庫引擎放棄索引進行全表掃描

SELECT * FROM t WHERE score IS NULL

優化方式:可以給字段添加默認值0對0值進行判斷。如下:

SELECT * FROM t WHERE score = 0

 

11. 盡量避免在where條件中等號的左側進行表達式、函數操作,會導致數據庫引擎放棄索引進行全表掃描

同第1個,單獨的列;

SELECT * FROM t2 WHERE score/10 = 9

SELECT * FROM t2 WHERE SUBSTR(username,1,2) = 'li'

優化方式:可以將表達式、函數操作移動到等號右側。如下:

SELECT * FROM t2 WHERE score = 10*9

SELECT * FROM t2 WHERE username LIKE 'li%'

 

12. 當數據量大時,避免使用where 1=1的條件。通常為了方便拼裝查詢條件,我們會默認使用該條件,數據庫引擎會放棄索引進行全表掃描

SELECT * FROM t WHERE 1=1

優化方式:用代碼拼裝sql時進行判斷,沒where加where,有where加and。

 

 

索引的好處:建立索引后,查詢時不會掃描全表,而會查詢索引表鎖定結果。

索引的缺點:在數據庫進行DML操作的時候,除了維護數據表之外,還需要維護索引表,運維成本增加。

應用場景:數據量比較大,查詢字段較多的情況。

索引規則:

1.選用選擇性高的字段作為索引,一般unique的選擇性最高;

2.復合索引:選擇性越高的排在越前面。(左前綴原則);

3.如果查詢條件中兩個條件都是選擇性高的,最好都建索引;

 

參考:

1. 索引的特點和應用場景

 2. SQL優化面試

 

二、查詢優化

1. 使用Explain進行分析

Explain 用來分析 SELECT 查詢語句,開發人員可以通過分析 Explain 結果來優化查詢語句。

比較重要的字段有:

  • select_type : 查詢類型,有簡單查詢、聯合查詢、子查詢等;

  • key : 使用的索引;

  • rows : 掃描的行數;

 

2. 優化數據訪問

  1. 減少請求的數據量

  • 只返回必要的列:最好不要使用 SELECT * 語句。

  • 只返回必要的行:使用 LIMIT 語句來限制返回的數據。

  • 緩存重復查詢的數據:使用緩存可以避免在數據庫中進行查詢,特別在要查詢的數據經常被重復查詢時,緩存帶來的查詢性能提升將會是非常明顯的。

  1. 減少服務器端掃描的行數

  • 最有效的方式是使用索引來覆蓋查詢。

 

3. 重構查詢方式

       1. 切分大查詢

一個大查詢如果一次性執行的話,可能一次鎖住很多數據、占滿整個事務日志、耗盡系統資源、阻塞很多小的但重要的查詢。

  1. 分解大連接查詢

將一個大連接查詢分解成對每一個表進行一次單表查詢,然后在應用程序中進行關聯,這樣做的好處有:

  • 讓緩存更高效:對於連接查詢,如果其中一個表發生變化,那么整個查詢緩存就無法使用。而分解后的多個查詢,即使其中一個表發生變化,對其它表的查詢緩存依然可以使用。

  • 分解成多個單表查詢,這些單表查詢的緩存結果更可能被其它查詢使用到,從而減少冗余記錄的查詢。

  • 減少鎖競爭

  • 應用層進行連接,可以更容易對數據庫進行拆分,從而更容易做到高性能和可伸縮。

  • 查詢本身效率也可能會有所提升。例如下面的例子中,使用 IN() 代替連接查詢,可以讓 MySQL 按照 ID 順序進行查詢,這可能比隨機的連接要更高效。

 

SELECT * FROM tab
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag='mysql';

SELECT * FROM tag WHERE tag='mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

 


免責聲明!

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



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