【調優向】MySQL調優必備-執行計劃explain與索引數據結構推演

準備工做

先建好數據庫表,演示用的MySQL表,建表語句:html

CREATE TABLE `emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `empno` int(11) DEFAULT NULL COMMENT '僱員工號',
  `ename` varchar(255) DEFAULT NULL COMMENT '僱員姓名',
  `job` varchar(255) DEFAULT NULL COMMENT '工做',
  `mgr` varchar(255) DEFAULT NULL COMMENT '經理的工號',
  `hiredate` date DEFAULT NULL COMMENT '僱用日期',
  `sal` double DEFAULT NULL COMMENT '工資',
  `comm` double DEFAULT NULL COMMENT '津貼',
  `deptno` int(11) DEFAULT NULL COMMENT '所屬部門號',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='僱員表';

CREATE TABLE `dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `deptno` int(11) DEFAULT NULL COMMENT '部門號',
  `dname` varchar(255) DEFAULT NULL COMMENT '部門名稱',
  `loc` varchar(255) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='部門表';

CREATE TABLE `salgrade` (
  `id` int(11) NOT NULL COMMENT '主鍵',
  `grade` varchar(255) DEFAULT NULL COMMENT '等級',
  `lowsal` varchar(255) DEFAULT NULL COMMENT '最低工資',
  `hisal` varchar(255) DEFAULT NULL COMMENT '最高工資',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='工資等級表';

CREATE TABLE `bonus` (
  `id` int(11) NOT NULL COMMENT '主鍵',
  `ename` varchar(255) DEFAULT NULL COMMENT '僱員姓名',
  `job` varchar(255) DEFAULT NULL COMMENT '工做',
  `sal` double DEFAULT NULL COMMENT '工資',
  `comm` double DEFAULT NULL COMMENT '津貼',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='獎金錶';
複製代碼

後續執行計劃,查詢優化,索引優化等等知識的演練,基於以上幾個表來操做。mysql

MySQL執行計劃

要進行SQL調優,你得知道要調優的SQL語句是怎麼執行的,查看SQL語句的具體執行過程,以加快SQL語句的執行效率。git

可使用explain + SQL語句來模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理SQL語句的。github

關於explain能夠看看官網介紹算法

explain的輸出格式

mysql> explain select * from emp;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
複製代碼

字段idselect_type等字段的解釋:sql

Column Meaning
id The SELECT identifier(該SELECT標識符)
select_type The SELECT type( 該SELECT類型)
table The table for the output row(輸出該行的表名)
partitions The matching partitions(匹配的分區)
type The join type(鏈接類型)
possible_keys The possible indexes to choose(可能的索引選擇)
key The index actually chosen(實際選擇的索引)
key_len The length of the chosen key(所選鍵的長度)
ref The columns compared to the index(與索引比較的列)
rows Estimate of rows to be examined(檢查的預估行數)
filtered Percentage of rows filtered by table condition(按表條件過濾的行百分比)
extra Additional information(附加信息)

id數據庫

select查詢的序列號,包含一組數字,表示查詢中執行select子句或者操做表的順序。緩存

id號分爲三類:服務器

  • 若是id相同,那麼執行順序從上到下
mysql> explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.lowsal and sg.hisal;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | e     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | NULL                                               |
|  1 | SIMPLE      | d     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | sg    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
複製代碼

這個查詢,用explain執行一下,id序號都是1,那麼MySQL的執行順序就是從上到下執行的。markdown

  • 若是id不一樣,若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
mysql> explain select * from emp e where e.deptno in (select d.deptno from dept d where d.dname = 'SALEDept');
+----+--------------+-------------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type  | table       | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+--------------+-------------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE       | <subquery2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |   100.00 | NULL                                               |
|  1 | SIMPLE       | e           | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |    50.00 | Using where; Using join buffer (Block Nested Loop) |
|  2 | MATERIALIZED | d           | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where                                        |
+----+--------------+-------------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
複製代碼

這個例子的執行順序是先執行id爲2的,而後執行id爲1的。

  • id相同和不一樣的,同時存在:相同的能夠認爲是一組,從上往下順序執行,在全部組中,id值越大,優先級越高,越先執行

仍是上面那個例子,先執行id爲2的,而後按順序從上往下執行id爲1的。

select_type

主要用來分辨查詢的類型,是普通查詢仍是聯合查詢仍是子查詢。

select_type Value JSON Name Meaning
SIMPLE None Simple SELECT (not using UNION or subqueries)
PRIMARY None Outermost SELECT
UNION None Second or later SELECT statement in a UNION
DEPENDENT UNION dependent (true) Second or later SELECT statement in a UNION, dependent on outer query
UNION RESULT union_result Result of a UNION.
SUBQUERY None First SELECT in subquery
DEPENDENT SUBQUERY dependent (true) First SELECT in subquery, dependent on outer query
DERIVED None Derived table
MATERIALIZED materialized_from_subquery Materialized subquery
UNCACHEABLE SUBQUERY cacheable (false) A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query
UNCACHEABLE UNION cacheable (false) The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY)
  • SIMPLE 簡單的查詢,不包含子查詢和union
mysql> explain select * from emp;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
複製代碼
  • primary 查詢中若包含任何複雜的子查詢,最外層查詢則被標記爲Primary
  • union 若第二個select出如今union以後,則被標記爲union
mysql> explain select * from emp where deptno = 1001 union select * from emp where sal < 5000;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type  | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | PRIMARY      | emp        | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where     |
|  2 | UNION        | emp        | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    33.33 | Using where     |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
複製代碼

這條語句的select_type包含了primaryunion

  • dependent union 跟union相似,此處的depentent表示union或union all聯合而成的結果會受外部表影響
  • union result 從union表獲取結果的select
  • dependent subquery subquery的子查詢要受到外部表查詢的影響
mysql> explain select * from emp e where e.empno  in ( select empno from emp where deptno = 1001 union select empno from emp where sal < 5000);
+----+--------------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type        | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+--------------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | PRIMARY            | e          | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | Using where     |
|  2 | DEPENDENT SUBQUERY | emp        | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where     |
|  3 | DEPENDENT UNION    | emp        | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where     |
| NULL | UNION RESULT       | <union2,3> | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | Using temporary |
+----+--------------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
複製代碼

這條SQL執行包含了PRIMARYDEPENDENT SUBQUERYDEPENDENT UNIONUNION RESULT

  • subquery 在select或者where列表中包含子查詢

舉例:

mysql> explain select * from emp where sal > (select avg(sal) from emp) ;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | PRIMARY     | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    33.33 | Using where |
|  2 | SUBQUERY    | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL        |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
複製代碼
  • DERIVED from子句中出現的子查詢,也叫作派生表
  • MATERIALIZED Materialized subquery?
  • UNCACHEABLE SUBQUERY 表示使用子查詢的結果不能被緩存

例如:

mysql> explain select * from emp where empno = (select empno from emp where deptno=@@sort_buffer_size);
+----+----------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type          | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+----------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | PRIMARY              | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | Using where |
|  2 | UNCACHEABLE SUBQUERY | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+----------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
複製代碼
  • uncacheable union 表示union的查詢結果不能被緩存

table

對應行正在訪問哪個表,表名或者別名,多是臨時表或者union合併結果集。

  1. 若是是具體的表名,則代表從實際的物理表中獲取數據,固然也能夠是表的別名
  2. 表名是derivedN的形式,表示使用了id爲N的查詢產生的衍生表
  3. 當有union result的時候,表名是union n1,n2等的形式,n1,n2表示參與union的id

type

type顯示的是訪問類型,訪問類型表示我是以何種方式去訪問咱們的數據,最容易想到的是全表掃描,直接暴力的遍歷一張表去尋找須要的數據,效率很是低下。

訪問的類型有不少,效率從最好到最壞依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

通常狀況下,得保證查詢至少達到range級別,最好能達到ref

  • all 全表掃描,通常狀況下出現這樣的sql語句並且數據量比較大的話那麼就須要進行優化

一般,能夠經過添加索引來避免ALL

  • index 全索引掃描這個比all的效率要好,主要有兩種狀況:
    • 一種是當前的查詢時覆蓋索引,即咱們須要的數據在索引中就能夠索取
    • 一是使用了索引進行排序,這樣就避免數據的重排序
  • range 表示利用索引查詢的時候限制了範圍,在指定範圍內進行查詢,這樣避免了index的全索引掃描,適用的操做符: =, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN()

官網上舉例以下:

SELECT * FROM tbl_name WHERE key_column = 10;

SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

  • index_subquery 利用索引來關聯子查詢,再也不掃描全表

value IN (SELECT key_column FROM single_table WHERE some_expr)

  • unique_subquery 該鏈接類型相似與index_subquery,使用的是惟一索引

value IN (SELECT primary_key FROM single_table WHERE some_expr)

  • index_merge 在查詢過程當中須要多個索引組合使用
  • ref_or_null 對於某個字段既須要關聯條件,也須要null值的狀況下,查詢優化器會選擇這種訪問方式

SELECT * FROM ref_table

WHERE key_column=expr OR key_column IS NULL;

  • fulltext 使用FULLTEXT索引執行join
  • ref 使用了非惟一性索引進行數據的查找

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;

  • eq_ref 使用惟一性索引進行數據查找

SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;

  • const 這個表至多有一個匹配行

SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name WHERE primary_key_part1=1 AND primary_key_part2=2;

例如:

mysql> explain select * from emp where id = 1;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | emp   | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
複製代碼
  • system 表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現

possible_keys

顯示可能應用在這張表中的索引,一個或多個,查詢涉及到的字段上若存在索引,則該索引將被列出,但不必定被查詢實際使用

key

實際使用的索引,若是爲null,則沒有使用索引,查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊

key_len

表示索引中使用的字節數,能夠經過key_len計算查詢中使用的索引長度,在不損失精度的狀況下長度越短越好

ref

顯示索引的哪一列被使用了,若是可能的話,是一個常數

rows

根據表的統計信息及索引使用狀況,大體估算出找出所需記錄須要讀取的行數,此參數很重要,直接反應的sql找了多少數據,在完成目的的狀況下越少越好

extra

包含額外的信息

  • using filesort 說明mysql沒法利用索引進行排序,只能利用排序算法進行排序,會消耗額外的位置
  • using temporary 創建臨時表來保存中間結果,查詢完成以後把臨時表刪除
  • using index 這個表示當前的查詢是覆蓋索引的,直接從索引中讀取數據,而不用訪問數據表。若是同時出現using where 代表索引被用來執行索引鍵值的查找,若是沒有,表示索引被用來讀取數據,而不是真的查找
  • using where 使用where進行條件過濾
  • using join buffer 使用鏈接緩存
  • impossible where where語句的結果老是false

MySQL索引基本知識

想要了解索引的優化方式,必需要對索引的底層原理有所瞭解。

索引的優勢

  1. 大大減小了服務器須要掃描的數據量
  2. 幫助服務器避免排序和臨時表
  3. 將隨機io變成順序io(提高效率)

索引的用處

  1. 快速查找匹配WHERE子句的行
  2. 從consideration中消除行,若是能夠在多個索引之間進行選擇,mysql一般會使用找到最少行的索引
  3. 若是表具備多列索引,則優化器可使用索引的任何最左前綴來查找行
  4. 當有錶鏈接的時候,從其餘表檢索行數據
  5. 查找特定索引列的min或max值
  6. 若是排序或分組時在可用索引的最左前綴上完成的,則對錶進行排序和分組
  7. 在某些狀況下,能夠優化查詢以檢索值而無需查詢數據行

索引的分類

索引的分類

MySQL索引數據結構推演

索引用於快速查找具備特定列值的行。

若是沒有索引,MySQL必須從第一行開始,而後通讀整個表以找到相關的行。

表越大花費的時間越多,若是表中有相關列的索引,MySQL能夠快速肯定要在數據文件中間查找的位置,而沒必要查看全部數據。這比順序讀取每一行要快得多。

既然MySQL索引能幫助咱們快速查詢到數據,那麼它的底層是怎麼存儲數據的呢?

幾種可能的存儲結構

hash

hash表的索引格式

hash表存儲數據的缺點:

  1. 利用hash存儲的話須要將全部的數據文件添加到內存,比較耗費內存空間
  2. 若是全部的查詢都是等值查詢,那麼hash確實很快,可是在實際工做環境中範圍查找的數據更多一些,而不是等值查詢,這種狀況下hash就不太適合了

事實上,MySQL存儲引擎是memory時,索引數據結構採用的就是hash表。

二叉樹

二叉樹的結構是這樣的:

二叉樹

二叉樹會由於樹的深度而形成數據傾斜,若是樹的深度過深,會形成io次數變多,影響數據讀取的效率。

AVL樹 須要旋轉,看圖例:

AVL樹

紅黑樹 除了旋轉操做還多了一個變色的功能(爲了減小旋轉),這樣雖然插入的速度快,可是損失了查詢的效率。

紅黑樹

二叉樹AVL樹紅黑樹 都會由於樹的深度過深而形成io次數變多,影響數據讀取的效率。

再來看一下 B樹

B樹特色:

  • 全部鍵值分佈在整顆樹中
  • 搜索有可能在非葉子結點結束,在關鍵字全集內作一次查找,性能逼近二分查找
  • 每一個節點最多擁有m個子樹
  • 根節點至少有2個子樹
  • 分支節點至少擁有m/2顆子樹(除根節點和葉子節點外都是分支節點)
  • 全部葉子節點都在同一層、每一個節點最多能夠有m-1個key,而且以升序排列

B樹存儲

圖例說明

每一個節點佔用一個磁盤塊,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指針,指針存儲的是子節點所在磁盤塊的地址。

兩個關鍵詞劃分紅的三個範圍域對應三個指針指向的子樹的數據的範圍域。

以根節點爲例,關鍵字爲 16 和 34,P1 指針指向的子樹的數據範圍爲小於 16,P2 指針指向的子樹的數據範圍爲 16~34,P3 指針指向的子樹的數據範圍爲大於 34。

查找關鍵字過程:

一、根據根節點找到磁盤塊 1,讀入內存。【磁盤 I/O 操做第 1 次】

二、比較關鍵字 28 在區間(16,34),找到磁盤塊 1 的指針 P2。

三、根據 P2 指針找到磁盤塊 3,讀入內存。【磁盤 I/O 操做第 2 次】

四、比較關鍵字 28 在區間(25,31),找到磁盤塊 3 的指針 P2。

五、根據 P2 指針找到磁盤塊 8,讀入內存。【磁盤 I/O 操做第 3 次】

六、在磁盤塊 8 中的關鍵字列表中找到關鍵字 28。

由此,咱們能夠得知B樹存儲的缺點:

  • 每一個節點都有key,同時也包含data,而每一個頁存儲空間是有限的,若是data比較大的話會致使每一個節點存儲的key數量變小
  • 當存儲的數據量很大的時候會致使深度較大,增大查詢時磁盤io次數,進而影響查詢性能

那麼MySQL索引數據結構是什麼呢

官網:Most MySQL indexes (PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT) are stored in B-trees

不要誤會,其實MySQL索引的存儲結構是B+樹,上面咱們一頓分析,知道B樹是不合適的。

mysql索引數據結構---B+Tree

B+Tree是在BTree的基礎之上作的一種優化,變化以下:

一、B+Tree每一個節點能夠包含更多的節點,這個作的緣由有兩個,第一個緣由是爲了下降樹的高度,第二個緣由是將數據範圍變爲多個區間,區間越多,數據檢索越快。

二、非葉子節點存儲key,葉子節點存儲key和數據。

三、葉子節點兩兩指針相互鏈接(符合磁盤的預讀特性),順序查詢性能更高。

B+樹存儲查找示意圖:

B+樹存儲

注意:

在B+Tree上有兩個頭指針,一個指向根節點,另外一個指向關鍵字最小的葉子節點,並且全部葉子節點(即數據節點)之間是一種鏈式環結構。

所以能夠對 B+Tree 進行兩種查找運算:一種是對於主鍵的範圍查找和分頁查找,另外一種是從根節點開始,進行隨機查找。

因爲B+樹葉子結點只存放data,根節點只存放key,那麼咱們計算一下,即便只有3層B+樹,也能製成千萬級別的數據。

你得知道的技(zhuang)術(b)名詞

假設有這樣一個表以下,其中id是主鍵:

mysql> select * from stu;
+------+---------+------+
| id   | name    | age  |
+------+---------+------+
|    1 | Jack Ma |   18 |
|    2 | Pony    |   19 |
+------+---------+------+
複製代碼

回表

咱們對普通列建普通索引,這時候咱們來查:

select * from stu where name='Pony';
複製代碼

因爲name建了索引,查詢時先找nameB+樹,找到主鍵id後,再找主鍵idB+樹,從而找到整行記錄。

這個最終會回到主鍵上來查找B+樹,這個就是回表

覆蓋索引

若是是這個查詢:

mysql> select id from stu where name='Pony';
複製代碼

就沒有回表了,由於直接找到主鍵id,返回就完了,不須要再找其餘的了。

沒有回表就叫覆蓋索引

最左匹配

再來以nameage兩個字段建組合索引(name, age),而後有這樣一個查詢:

select * from stu where name=? and age=?
複製代碼

這時按照組合索引(name, age)查詢,先匹配name,再匹配age,若是查詢變成這樣:

select * from stu where age=?
複製代碼

直接不按name查了,此時索引不會生效,也就是不會按照索引查詢---這就是最左匹配原則。

加入我就要按age查,還要有索引來優化呢?能夠這樣作:

  • (推薦)把組合索引(name, age)換個順序,建(age, name)索引
  • 或者直接把age字段單獨建個索引

索引下推

可能也叫謂詞下推。。。

select t1.name,t2.name from t1 join t2 on t1.id=t2.id
複製代碼

t1有10條記錄,t2有20條記錄。

咱們猜測一下,這個要麼按這個方式執行:

先t1,t2按id合併(合併後20條),而後再查t1.name,t2.name

或者:

先把t1.name,t2.name找出來,再按照id關聯

若是不使用索引條件下推優化的話,MySQL只能根據索引查詢出t1,t2合併後的全部行,而後再依次比較是否符合所有條件。

當使用了索引條件下推優化技術後,能夠經過索引中存儲的數據判斷當前索引對應的數據是否符合條件,只有符合條件的數據纔將整行數據查詢出來。

小結

  1. Explain 爲了知道優化SQL語句的執行,須要查看SQL語句的具體執行過程,以加快SQL語句的執行效率。
  2. 索引優勢及用處。
  3. 索引採用的數據結構是B+樹。
  4. 回表,覆蓋索引,最左匹配和索引下推。

首發公衆號 行百里er ,歡迎老鐵們關注閱讀指正。代碼倉庫 GitHub github.com/xblzer/Java…

相關文章
相關標籤/搜索