數據庫設計與優化 - 結合執行計劃MySQL語句的11大優化策略

背景mysql

全球訪問量最大的 20 家網站,絕大多數使用 MySQL,有兩個特例的 live.com 和 bing 是微軟旗下的網站。它使用的是 MSSQL,並非他們使用不了 MySQL,而是他要支持本身的數據庫。毫無疑問MySQL是當今很是流行的關係數據庫之一,不只由於其絕大多數版本的開源,並且支持多存儲引擎、快速、穩定地運行於各類服務器環境。MySQL查詢分析優化引擎做爲其中核心模塊的一部分,佔有舉足輕重的地位,所以咱們今天瞭解和研究它就很是重要了。sql

image.png


MySQL服務器操做層架構數據庫

image.png

MySQL語句的優化就發生MySQL Server服務器架構的操做層,這層具體的執行流程是:緩存

image.png

這層主要的功能是: SQL 語句的解析、優化,緩存的查詢,MySQL 內置函數的實現,跨存儲引擎功能(所謂跨存儲引擎就是說每一個引擎都需提供的功能(引擎需對外提供接口)),例如:存儲過程、觸發器、視圖等。服務器

1.若是是查詢語句(select 語句),首先會查詢緩存是否已有相應結果,有則返回結果,無則進行下一步(若是不是查詢語句,一樣調到下一步);數據結構

2.解析查詢,建立一個內部數據結構(解析樹),這個解析樹主要用來 SQL 語句的語義與語法解析;架構

3.優化:優化 SQL 語句,例如重寫查詢,決定表的讀取順序,以及選擇須要的索引等。這一階段用戶是能夠查詢的,查詢服務器優化器是如何進行優化的,便於用戶重構查詢和修改相關配置,達到最優化。這一階段還涉及到存儲引擎,優化器會詢問存儲引擎,好比某個操做的開銷信息、是否對特定索引有查詢優化等。ide

十一大優化策略
函數

演示準備mysql索引

image.png

用以上演示道具來講明十一經典優化策略以下:

策略1、索引字段儘可能全值匹配

-- 查詢1

EXPLAIN SELECT * FROM employee WHERE `name`='joye'; -- 走索引

image.png

-- 查詢2

EXPLAIN SELECT * FROM employee WHERE `name`='joye' AND age=25; -- 走索引

image.png

-- 查詢3

EXPLAIN SELECT * FROM employee WHERE `NAME`='joye' AND age=25 AND pos='dev'; -- 走索引

image.png

以上三種查詢方式,查詢3的效率最高,索引的使用程度也最高。在表中創建索引後,能用索引的要儘可能都要用上。

策略2、最佳左前綴法則

若是建立的索引爲複合索引,要遵照最左前綴法則。查詢從索引的最左前列開始而且不要跳過索引中的列。

-- 查詢1

EXPLAIN SELECT * FROM employee WHERE age=20  AND pos='dev'; -- 不走索引

image.png

-- 查詢2

EXPLAIN SELECT * FROM employee WHERE pos='dev'; -- 不走索引

image.png

-- 查詢3

EXPLAIN SELECT * FROM employee WHERE `name`='Joye'; -- 走索引

image.png

以上查詢只有查詢3才走索引。最佳左前綴法則能夠理解成火車的車頭、中間車箱、車尾的關係。

策略3、不在索引列上作任何操做

在索引列上計算、函數、類型轉換等會致使索引失效,轉向全表掃描。

-- 查詢1

EXPLAIN  SELECT *  FROM  employee  WHERE `name`='Joye'; -- 走索引

image.png

-- 查詢2

EXPLAIN  SELECT *  FROM  employee  WHERE LEFT(`name`,4)='Joye';  -- 不走索引

image.png

-- 查詢3

EXPLAIN  SELECT *  FROM  employee  WHERE `age`*2 = 13;  -- 不走索引

image.png

在索引字段上使用函數、任何計算表達式均會致使索引失效。

策略4、儘可能多用覆蓋索引

儘可能使用覆蓋索引(只訪問索引列的查詢,查詢列和索引列一致),減小select開銷。所有數據直接經過索引就能獲取到,大大提升查詢效率。

-- 查詢1

EXPLAIN  SELECT  age,pos  FROM  employee  WHERE `name` = 'joye';  -- 走索引

image.png

-- 查詢2

EXPLAIN  SELECT  pos  FROM  employee  WHERE `name` = 'joye';  -- 走索引

image.png

-- 查詢3

EXPLAIN  SELECT  age,add_time  FROM  employee  WHERE `name` = 'joye';  -- 不走索引

image.png

策略5、範圍條件放最後

查詢優化器不會使用索引中範圍條件右邊的列,因此範圍條件放最後能被主動採用。

-- 查詢1

EXPLAIN  SELECT  *  FROM  employee  WHERE  `NAME`='joye' AND  age=22  AND pos='manager'; -- 走索引

image.png

-- 查詢2

EXPLAIN  SELECT  *  FROM  employee  WHERE  `NAME`='joye' AND  age>22 AND  pos='manager';-- 不充分走索引

image.png

-- 查詢3

EXPLAIN  SELECT  *  FROM  employee  WHERE  `NAME`='joye' AND  pos='manager' AND  age>22; -- 充分走索引

image.png

策略6、不等於(! <>) 要慎用

mysql在使用不等於(!=  或者 <>)的時候沒法使用索引,致使全表掃描

-- 查詢1

EXPLAIN  SELECT  *  FROM  employee  WHERE  `name` != 'joye'; --  不走索引

image.png

-- 查詢2

EXPLAIN  SELECT  *  FROM  employee  WHERE  NAME <>'joye';  --  不走索引

image.png

若要使用不等號,儘可能採用覆蓋索引;

-- 查詢3

EXPLAIN  SELECT  `name`,age,pos  FROM  employee  WHERE  NAME  != 'joye'; --  走索引

image.png

-- 查詢4

EXPLAIN  SELECT  NAME,age,pos  FROM  employee  WHERE  NAME  <> 'joye'; --  走索引

image.png

策略7、IN/NOT IN要慎用

-- 查詢1

EXPLAIN SELECT * FROM employee WHERE `name` IN('joye','9000');  -- 不走索引

image.png

-- 查詢2

EXPLAIN SELECT * FROM employee WHERE `name` NOT  IN('joye','9000'); -- 不走索引

image.png

查詢1和查詢2不走索引的緣由是IN/NOT IN 匹配讓索引失效,轉向全表掃描 。若須要使用IN/NOT IN,則同時儘可能採用覆蓋索引或就使用場景使用JOIN連表方式

-- 查詢3

EXPLAIN SELECT age,pos FROM employee WHERE `name` IN('joye','9000'); -- 走索引

image.png

-- 查詢4

EXPLAIN SELECT age,pos FROM employee WHERE `name` NOT IN('joye','9000'); -- 充分使用索引

image.png

策略8、NULL/NOT NULL有影響

索引字段爲null 和 not null 對索引的影響,  可能致使索引失效(分狀況)。

-- 查詢1

EXPLAIN SELECT * FROM  employee WHERE `name` IS NULL; -- 不走索引

image.png

-- 查詢2

EXPLAIN SELECT * FROM  employee WHERE `name` IS NOT NULL; -- 不走索引

image.png

這時設置`name`字段容許爲null

-- 查詢3

EXPLAIN  SELECT  * FROM  employee2  WHERE  NAME  IS  NULL; -- 走索引

image.png

策略9、LIKE查詢要當心

LIKE以通配符開頭(‘%abc ’)mysql索引失效會變成全表掃描操做。

-- 查詢1

EXPLAIN  SELECT  *  FROM  employee  WHERE  `name`  LIKE  '%july%' -- 不走索引

image.png

-- 查詢2

EXPLAIN  SELECT  *  FROM  employee  WHERE   `name` LIKE  '%july' -- 不走索引

image.png

-- 查詢3

EXPLAIN  SELECT  *  FROM  employee  WHERE   `name` LIKE  'july%'-- 走索引

image.png

策略10、字符類型字段加引號

字符竄不加引號會致使索引失效。

-- 查詢1

EXPLAIN  SELECT  *  FROM  employee  WHERE  `name` = 9000;  -- 不走索引

image.png

-- 查詢2

EXPLAIN  SELECT  *  FROM  employee  WHERE  `name` = '9000'  -- 走索引

image.png

策略11、OR改UNION 效率高

WHERE查詢或子查詢條件中使用OR,會致使索引失效,轉向全表數據掃描。

-- 查詢1

EXPLAIN SELECT  *  FROM  employee  WHERE  `name`='joye'  OR  `name`='andy3'; --  不走索引

image.png

-- 查詢2

EXPLAIN

SELECT  *  FROM  employee  WHERE  `name`='joye'

UNION

SELECT  *  FROM  employee  WHERE   `name`='andy3'; --  走索引

image.png

總結

以上僅爲SQL語句優化領域的關鍵優化指標和技巧。在具體項目的優化中,咱們可能會綜合使用以上多個策略和手段完成一個SQL的優化;如何用好這些策略徹底取決於咱們在項目實戰中按部就班的優化、嘗試、摸索、總結。之後會在項目實踐中,分享更多綜合性大數據問題優化實戰案例,請繼續關注!

相關文章
相關標籤/搜索