MySQL day04 索引及執行計劃

索引介紹

1.索引作用
提供了類似於書中目錄的作用,目的是爲了優化查詢

2.索引的種類(算法)

B樹索引
Hash索引
R樹
Full text
GIS 

3.MySQL B+TREE 索引構建過程
理論上三次IO

3.1 聚簇索引BTREE結構(InnoDB獨有)
區 ===》 簇

構建前提

  1. 建表時,指定了主鍵列,MySQL InnoDB會將主鍵作爲聚簇索引列,比如
  2. 如果沒有主鍵,會自動選擇唯一鍵unique作爲聚集索引.
  3. 以上都沒用,生成隱藏聚簇索引

作用
有了聚簇索引之後,將來插入的數據行,在同一個區內,都會按照ID值的順序,有序在磁盤存儲數據
在這裏插入圖片描述

3.2 輔助索引BTREE結構
說明:使用普通列作爲條件構建的索引。
作用:優化非聚簇索引列之外的查詢

輔助索引(S)怎麼構建B樹結構的?

(1). 索引是基於表中,(索引鍵)的值生成的B樹結構
(2). 首先提取此列所有的值,進行自動排序
(3). 將排好序的值,均勻的分佈到索引樹的葉子節點中(16K)
(4). 然後生成此索引鍵值所對應得後端數據頁的指針
(5). 生成枝節點和根節點,根據數據量級和索引鍵長度,生成合適的索引樹高度
id  name  age  gender
select  *  from  t1 where id=10;
問題: 基於索引鍵做where查詢,對於id列是順序IO,但是對於其他列的查詢,可能是隨機IO.

輔助索引 查找過程
在這裏插入圖片描述

輔助索引只能查出name=s 對應 id=8和id=25
在這裏插入圖片描述如果查找的值在輔助索引都有就不用回到聚集索引找,select id,name

輔助索引得到的id值回到聚集索引 找
在這裏插入圖片描述

聚集索引和輔助索引構成區別

聚集索引只能有一個,非空唯一,一般時主鍵
輔助索引,可以有多個,時配合聚集索引使用的
聚集索引葉子節點,就是磁盤的數據行存儲的數據頁
MySQL是根據聚集索引,組織存儲數據,數據存儲時就是按照聚集索引的順序進行存儲數據
輔助索引,只會提取索引鍵值,進行自動排序生成B樹結構

輔助索引細分

1.普通的單列輔助索引
2.聯合索引
多個列作爲索引條件,生成索引樹,理論上設計的好的,可以減少大量的回表
查詢
說明:使用多列組合一個索引
聯合索引,注意最左原則。 idx(a,b,c)1)查詢條件中,必須要包含最左列,上面例子就是a列
(2)建立聯合索引時,一定要選擇重複值少的列,作爲最左列
例如:idx(a,b,c)
全部覆蓋:
select * from t1 where a= and b= and c=
select * from t1 where a in


3.唯一索引
索引列的值都是唯一的.

關於索引樹的高度受什麼影響

              解決方法
1. 數據行過多:分表,分庫,分佈式
2. 索引列值過長 :前綴索引
3. 數據類型: 選擇合適的數據類型
變長長度字符串,使用了char,解決方案:變長字符串使用varchar
enum類型的使用enum ('山東','河北','黑龍江','吉林','遼寧','陝西'......)
                                         1      2      3

索引的管理命令

什麼時候創建索引?

按照業務語句的需求創建合適的索引。
並不是將所有列都建立索引,不是索引越多越好
將索引建立在,經常 where group by order by join on …的條件

爲什麼不能亂建索引?
1.如果冗餘索引過多,表的數據變化的時候,很有可能會導致索引頻繁更新。會阻塞很多正常的業務更新的請求。
2.索引過多,會導致優化器選擇出現偏差

建索引原則

(1) 必須要有主鍵,如果沒有可以做爲主鍵條件的列,創建無關列
(2) 經常做爲where條件列  order by  group by  join on, distinct 的條件(業務:產品功能+用戶行爲)
(3) 最好使用唯一值多的列作爲索引,如果索引列重複值較多,可以考慮使用聯合索引
(4) 列值長度較長的索引列,我們建議使用前綴索引.
(5) 降低索引條目,一方面不要創建沒用索引,不常使用的索引清理,percona toolkit(xxxxx)
(6) 索引維護要避開業務繁忙期



❤沒有查詢條件,或者查詢條件沒有建立索引
select * from tab;       全表掃描。
select  * from tab where 1=1;
在業務數據庫中,特別是數據量比較大的表。
是沒有全表掃描這種需求。
1、對用戶查看是非常痛苦的。
2、對服務器來講毀滅性的。
(1select * from tab;
SQL改寫成以下語句:
select  * from  tab  order by  price  limit 10 ;    需要在price列上建立索引
(2select  * from  tab where name='zhangsan'          name列沒有索引
改:
1、換成有索引的列作爲查詢條件
2、將name列建立索引

管理命令

1.查詢表的索引情況

mysql> desc city;
key:PRI主鍵索引(聚簇索引) MUL輔助索引 UNI唯一索引
mysql> show index from city;

2.建立索引

分析業務語句

語法:alter table 表名 add index 索引名(列名);
mysql> alter table city add index idx_na(name);
聯合索引:mysql> alter table city add index idx_n_c(name,countrycode);
前綴索引,比如字段district的前5個字符構建索引  mysql> alter table city add index idx_d(district(5));

聯合索引創建
在這裏插入圖片描述

3.刪除索引

mysql> alter table city drop index idx_na;
mysql> alter table city drop index idx_d;
mysql> alter table city drop index idx_n_c;

壓力測試體現索引功能

100萬數據

1.導入100w的測試表

mysql> source t100w.sql
mysql> show index from t100w;

在這裏插入圖片描述

2.壓測命令:未建立索引

通過slap模仿100個用戶連接,同時查詢,一共執行200次。 每個人運行2#mysqlslap --defaults-file=/etc/my.cnf \
--concurrency=100 --iterations=1 --create-schema='test' \
--query="select * from test.t100w where k2='780p'" engine=innodb \
--number-of-queries=200 -uroot -p123456-verbose

在這裏插入圖片描述

3.壓測命令:建立索引

可以發現where k2

mysql> use mysql
mysql> alter table t100w add index idx_k2(k2);

在這裏插入圖片描述

執行計劃

(1)獲取到的是優化器選擇完成的,他認爲代價最小的執行計劃.
作用: 語句執行前,先看執行計劃信息,可以有效的防止性能較差的語句帶來的性能問題.
如果業務中出現了慢語句,我們也需要藉助此命令進行語句的評估,分析優化方案。
(2) select 獲取數據的方法

  1. 全表掃描(應當儘量避免,因爲性能低)
  2. 索引掃描
  3. 獲取不到數據

執行計劃顯示結果的認識
在這裏插入圖片描述
全盤掃描:不用任何的索引。 ALL
where 1=1;
where countrycode like ‘%ch%’;
where countrycode not in (‘CHN’,‘USA’);
where countrycode !=‘CHN’;

如果是主鍵 <> NOT IN 是可以走range索引的

索引掃描(越右越優先):index < range < ref < eq_ref < const(system)

mysql> desc sql語句; 可以查看到是什麼類型

1.type詳解

從左到右性能依次變好.
ALL  :  
全表掃描,不走索引  ALL
例子:
1. 查詢條件列,沒有索引
SELECT * FROM t_100w WHERE k2='780P';  
2. 查詢條件出現以下語句(輔助索引列)
USE world 
DESC city;
DESC SELECT * FROM city WHERE countrycode <> 'CHN';
DESC SELECT * FROM city WHERE countrycode NOT IN ('CHN','USA');
DESC SELECT * FROM city WHERE countrycode LIKE '%CH%';
注意:對於聚集索引列,使用以上語句,依然會走索引
DESC SELECT * FROM city WHERE id <> 10;

————————————————————————————————————————————————————————————————————————————

INDEX  :
全索引掃描
1. 查詢需要獲取整個索引樹種的值時:
DESC  SELECT countrycode  FROM city;

2. 聯合索引中,任何一個非最左列作爲查詢條件時:
idx_a_b_c(a,b,c)  ---> a  ab  abc

SELECT * FROM t1 WHERE b 
SELECT * FROM t1 WHERE c    


RANGE :
索引範圍掃描 
輔助索引> < >= <= LIKE IN OR 
如果是主鍵 <>  NOT IN  是可以走range索引的

例子:
1. DESC SELECT * FROM city WHERE id<5;
2. DESC SELECT * FROM city WHERE countrycode LIKE 'CH%';
3. DESC SELECT * FROM city WHERE countrycode IN ('CHN','USA');

注意: 
12例子中,可以享受到B+樹的優勢,但是3例子中是不能享受的.
所以,我們可以將3號列子改寫:

DESC SELECT * FROM city WHERE countrycode='CHN'
UNION ALL 
SELECT * FROM city WHERE countrycode='USA';
默認地,UNION 操作符選取不同的值。如果允許重複的值,請使用 UNION ALL。


ref: 
非唯一性索引,輔助等值查詢
DESC SELECT * FROM city WHERE countrycode='CHN';


eq_ref: 
在多表連接時,索引是主鍵或唯一非 NULL 索引時, 將使用該值
DESC SELECT b.name,a.name FROM city AS a 
JOIN country AS b 
ON a.countrycode=b.code 
WHERE a.population <100;
DESC country


const(system):
select * from city where id=10;
id是主鍵
DESC SELECT * FROM city WHERE id=10;

2.其他字段解釋

extra: 
filesort ,文件排序.
SHOW INDEX FROM city;
ALTER TABLE city ADD INDEX CountryCode(CountryCode);
ALTER TABLE city DROP INDEX idx_c_p;

DESC SELECT * FROM city WHERE countrycode='CHN'  ORDER BY population 

ALTER TABLE city ADD INDEX idx_(population);
DESC SELECT * FROM city WHERE countrycode='CHN'  ORDER BY population 
ALTER TABLE city ADD INDEX idx_c_p(countrycode,population);
ALTER TABLE city DROP INDEX idx_;
ALTER TABLE city DROP INDEX CountryCode;
DESC SELECT * FROM city WHERE countrycode='CHN'  ORDER BY population 

結論: 
1.當我們看到執行計劃extra位置出現filesort,說明由文件排序出現
2.觀察需要排序(ORDER BY,GROUP BY ,DISTINCT )的條件,有沒有索引
3. 根據子句的執行順序,去創建聯合索引

索引優化效果測試:
優化前:
[root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf \
> --concurrency=100 --iterations=1 --create-schema='oldboy' \
> --query="select * from oldboy.t_100w where k2='780P'" engine=innodb \
> --number-of-queries=2000 -uroot -p123 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
    Running for engine rbose
    Average number of seconds to run all queries: 701.743 seconds
    Minimum number of seconds to run all queries: 701.743 seconds
    Maximum number of seconds to run all queries: 701.743 seconds
    Number of clients running queries: 100
    Average number of queries per client: 20

優化後:
[root@db01 ~]# mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='oldboy' --query="select * from oldboy.t_100w where k2='780P'" engine=innodb --number-of-queries=2000 -uroot -p123 -verbose
mysqlslap: [Warning] Using a password on the command line interface can be insecure.
Benchmark
    Running for engine rbose
    Average number of seconds to run all queries: 0.190 seconds
    Minimum number of seconds to run all queries: 0.190 seconds
    Maximum number of seconds to run all queries: 0.190 seconds
    Number of clients running queries: 100
    Average number of queries per client: 20

聯合索引:
1. SELECT * FROM t1  WHERE a=    b=   
我們建立聯合索引時:
ALTER TABLE t1 ADD INDEX idx_a_b(a,b);  
ALTER TABLE t1 ADD INDEX idx_b_a(b,a);  
以上的查詢不考慮索引的順序,優化器會自動調整where的條件順序
注意: 索引,我們在這種情況下建索引時,需要考慮哪個列的唯一值更多,哪個放在索引左邊.

2.  如果出現where 條件中出現不等值查詢條件
DESC  SELECT * FROM t_100w WHERE num <1000 AND k2='DEEF';
我們建索引時:
ALTER TABLE t_100w ADD INDEX idx_2_n(k2,num);
語句書寫時
DESC  SELECT * FROM t_100w WHERE  k2='DEEF'  AND  num <1000 ;
3. 如果查詢中出現多子句
我們要按照子句的執行順序進行建立索引.

explain(desc)使用場景(面試題)

題目意思:  我們公司業務慢,請你從數據庫的角度分析原因
1.mysql出現性能問題,我總結有兩種情況:
(1)應急性的慢:突然夯住
應急情況:數據庫hang(卡了,資源耗盡)
處理過程:
1.show processlist;  獲取到導致數據庫hang的語句
2. explain 分析SQL的執行計劃,有沒有走索引,索引的類型情況
3. 建索引,改語句
(2)一段時間慢(持續性的):
(1)記錄慢日誌slowlog,分析slowlog
(2)explain 分析SQL的執行計劃,有沒有走索引,索引的類型情況
(3)建索引,改語句
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章