MySql數據結構(索引)


目錄

一:MySQL索引與慢查詢優化

1.什么是索引?
簡單的理解為可以幫助你加快數據查詢速度的工具
也可以把索引比喻成書的目錄,它能讓你更快的找到自己想要的內容
2.索引類型分類介紹
#===========B+樹索引(等值查詢與范圍查詢都快)
二叉樹->平衡二叉樹->B樹->B+樹
        
#===========HASH索引(等值查詢快,范圍查詢慢)
將數據打散再去查詢

#===========FULLTEXT:全文索引 (只可以用在MyISAM引擎)
通過關鍵字的匹配來進行查詢,類似於like的模糊匹配
like + %在文本比較少時是合適的
但是對於大量的文本數據檢索會非常的慢
全文索引在大量的數據面前能比like快得多,但是准確度很低
百度在搜索文章的時候使用的就是全文索引,但更有可能是ES

RTREE: 		R樹索引
3.不同的存儲引擎支持的索引類型也不一樣
innDB存儲引擎
支持事務,支持行級別鎖定,支持 B-tree(默認)、Full-text 等索引,不支持 Hash 索引;

mylSAM存儲引擎
不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;

Memory存儲引擎
不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
  • 因為mysql默認的存儲引擎是innodb,而innodb存儲引擎的索引模型/結構是B+樹,所以我們着重介紹B+樹,那么大家最關注的問題來了:

B+樹索引到底是如何加速查詢的呢?

二:索引的數據結構

innodb存儲引擎默認的索引結構為B+樹,而B+樹是由二叉樹、平衡二叉樹、B樹再到B+樹一路演變過來的

1.二叉樹(每個節點只能分兩個叉)

image

2.數據結構(B樹)
b樹		:精確查詢 三次IO操作
案例:
    select * from user where id=38
    
b樹		:范圍內查詢 九次IO操作
案例:
    select * from where id > 38 and id < 73;
 
總結b樹:
    b樹查詢的次數又b樹的層次決定

image

3.b+樹 范圍查詢 五次IO操作(葉節點指針)
b+樹		: 范圍查詢 五次IO操作(葉節點指針)
    id > 38 and id < 73

指針分為兩個部分:
pdata	: 前面存數據
pnext	: 存下面一個指針的位置

總結b+樹:
	b+樹依靠指針比b樹查詢速度更快,也是MySQ目前L默認使用的索引

image

4.b*樹(枝節點也添加了指針)
b*樹(枝節點也添加了指針)
指針的作用:
添加指針是為了加快范圍查詢的速度

image

5.總結(索引)
索引的作用:
	索引就是為了提供數據的查詢速度
	在計算機底層的表現形式就是一些數據結構(樹)
	
數據結構:
二叉樹		 : 每個節點只能分兩個叉
b樹		  : 枝節點和葉節點沒有指針
b+樹		  : 葉節點添加指針
b*樹		  : 枝節點添加了指針(葉節點也有)

指針添加的作用:
指針的添加主要是為了解決范圍查詢的問題
精確查找取決於樹的高度

索引的必要性:
將某個字段添加成索引就相當於依據該字段建立了一顆b+樹從而加快查詢速度
如果某個字段沒有添加索引 那么依據該字段查詢數據會非常的慢(一行行查找)
6.索引的分類
1.primary key
	主鍵索引除了有加速查詢的效果之外 還具有一定的約束條件
2.unique key
	唯一鍵索引 除了有加速查詢的效果之外 還具有一定的約束條件
3.index key
	普通索引 只有加速查詢的效果 沒有額外約束
    
    
注意外鍵不是索引 它僅僅是用來創建表與表之間關系的
foreign key 

三:操作索引

1.創建唯一索引需要提前排查是否有重復數據
select count(字段) from t1
select count(distinct(字段)) from t1
2.查看當前表內部索引值
show index from t1;

image

3.主鍵索引(指定索引)
alter table t1 add primary key pri_id(id);  # 以id字段為索引

pri_id	: 索引名<見名之意>

再次查看當前內部索引值
show index from t1\G;

image

4.查詢以id索引字段,此時加速查詢(如果使用name字段查詢,就還是一行一行查詢)
select * from t1 where id=3

image

5.唯一索引
alter table t1 add unique key uni_pwd(pwd)

1.測試使用唯一索引

image

6.報錯原因
使用唯一索引時,指定字段是唯一索引時,該字段如果有重復,使用唯一索引會報錯。

四:解決字段重復

1.創建唯一索引需要提前排查是否有重復數據
1.統計當前字段個數
select count(pwd) from t1

image

2.去重pwd字段重復 排除重復數據(進行對比是否有重復數據)
select count(distinct(pwd)) from t1

image

3.刪除重復數據

delete from t1 where id=4;

4.指定唯一索引(pwd字段索引)

alter table t1 add unique key uni_pwd(pwd);

5.查看當前所有索引

show index from t1\G;
image

6.普通索引(只能加速查詢,沒有其他約束條件)
alter table t1 add index idx_name(name)

image

7.刪除索引
alter table 表名 drop index 索引名;
8.前綴索引(屬於普通索引)
前綴索引的作用:
避免對大列建索引(數據很多情況),如果有就使用前綴索引    	
比如:
    博客內容 百度搜索內容等
    
根據字段前N個字符建立索引
alter table t1 add index idx_name(name(10))
9.聯合索引(屬於普通索引)
聯合索引作用:
相親平台 搜索心儀對象的時候 《女,富婆,未婚,漂亮,1.69》

遵循:最左匹配原則
例:
    where a.女生 and b.身高 and c.體重 and d.身材好
    index(a.b.c)
特點: 前綴生效特性
a,ab,ac,abc,abcd 可以走索引或部分走索引
b bc bcd c d ba... 不走索引
10.創建聯合索引(前綴生效特性)
alter table t1 add index idx_all(id,name,pwd)

image

五:explain句式(全表掃描-索引掃描)

1.全表掃描與索引掃描區別
全表掃描(在explain語句結果中type為ALL)	
		不走索引 一行行查找數據 效率極低 生產環境下盡量不要書寫類似SQL

索引掃描(const)
		走索引 加快數據查詢 建議書寫該類型SQL

注意:
生成過程中,MySQL在使用全表掃描時的性能是極差的,所有MySQL盡量避免出現全表掃描。

explain就是幫助我們查看SQL語句屬於那種掃描(全表掃描 還是 索引掃描)

2.explain命令使用格式:
explain select * from t1 where id=2;
3.使用explain驗證全表掃描存在

image

4.使用explain驗證索引掃描存在

image

5.什么時候出現全表掃描?
	1.業務確實要獲取所有數據
	2.不走索引導致的全盤掃描
	3.沒索引
	4.索引創建有問題
	5.語句有問題

6.常見的索引掃描類型
    1)index
    2)range
    3)ref
    4)eq_ref
    5)const
    6)system
    7)null
從上到下,性能從最差到最好,我們認為至少要達到range級別
7.索引掃描(內容解析)
index	: index與ALL區別為index類型只遍歷索引樹

range	: 索引范圍掃描,對索引的掃描開始於某一點,返回匹配值域的行。顯而易見的索引范圍掃描是帶有between或者where子句里帶有<,>查詢。<范圍>

案例演示: 	
mysql> alter table city add index idx_city(population);
 	
mysql> explain select * from city where population>30000000;

ref		: 使用非唯一索引掃描或者唯一索引的前綴掃描,返回匹配某個單獨值得記錄 行。<精確>

案例演示: 	
mysql> alter table city drop key idx_code;
 	
mysql> explain select * from city where countrycode='chn';
 	
mysql> explain select * from city where countrycode in ('CHN','USA');
 	
mysql> explain select * from city where countrycode='CHN' union all select * from city where countrycode='USA';

eq_ref	 : 類似ref,但不加前綴,區別就在使用得索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連接中使用primary key或者 unique key作為關聯條件A。

案例演示: 	
join B
 	
on A.sid=B.sid


const,system : 當MySQL查詢某部分進行優化,並轉換為一個常量是,使用這些類型訪問。

案例演示:
mysql> explain select * from city where id=1000;

NULL	: MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列里選取最小值可以通過單獨索引查找完成。

案例演示:
mysql> explain select * from city where id=1000000000000000000000000000;
8.在業務數據庫中,特別是數據量比較大的表,是沒有全表掃描這種需求。
1.對用戶查看時非常痛苦的
2.對服務器來講毀滅性的
3.SQL改寫成以下語句:
#情況1
#全表掃描
select * from table;
#需要在price列上建立索引
selec * from tab order by price limit 10;
#情況2
#name列沒有索引
select * from table where name='zhangsan';
1、換成有索引的列作為查詢條件
2、將name列建立索引

六:不走索引情況(起碼記憶四條及以上)

1.沒有查詢條件,或者查詢條件沒有建立索引
全表掃描
select * from table;
select * from tab where 1=1;
2.查詢結果集是原表中的大部分數據(25%以上)有可能不走索引
mysql> explain select * from city where population>3000 order by population;
1)如果業務允許,可以使用limit控制。
2)結合業務判斷,有沒有更好的方式。如果沒有更好的改寫方案就盡量不要在mysql存放這個數據了,放到redis里面。
3.索引本身失效,統計數據不真實
索引有自我維護的能力。
對於表內容變化比較頻繁的情況下,有可能會出現索引失效。
重建索引就可以解決
4.查詢條件使用函數在索引列上或者對索引列進行運算,運算包括(+,-,*等)
例子:
    錯誤的例子:	select * from test where id-1=9;
    正確的例子:  select * from test where id=10;
5.隱式轉換導致索引失效.這一點應當引起重視.也是開發中經常會犯的錯誤
eg:字段是字符類型 查詢使用整型
mysql> create table test (id int ,name varchar(20),telnum varchar(10));
mysql> insert into test values(1,'zs','110'),(2,'l4',120),(3,'w5',119),(4,'z4',112);
mysql> explain select * from test where telnum=120;
mysql> alter table test add index idx_tel(telnum);
mysql> explain select * from test where telnum=120;
mysql> explain select * from test where telnum=120;
mysql> explain select * from test where telnum='120';
  • 測試隱式轉換導致失效(類型轉錯成int類型)
    image

  • 糾正隱式轉換導致的失敗(傳入正確的 字符串類型)
    image

6.<> ,not in 不走索引
單獨的>,<,in 有可能走,也有可能不走,和結果集有關,盡量結合業務添加limit、or或in盡量改成union
7.like "%_" 百分號在最前面不走
#走range索引掃描
EXPLAIN SELECT * FROM teltab WHERE telnum LIKE '31%';
#不走索引
EXPLAIN SELECT * FROM teltab WHERE telnum LIKE '%110';
8.單獨引用聯合索引里非第一位置的索引列(最多匹配原則,第一個不滿足,剩下的就不滿足了)
CREATE TABLE t1 (id INT,NAME VARCHAR(20),age INT ,sex ENUM('m','f'),money INT);
ALTER TABLE t1 ADD INDEX t1_idx(money,age,sex);
DESC t1
SHOW INDEX FROM t1
#走索引的情況測試
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 AND sex='m';
#部分走索引
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30;
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND sex='m';
#不走索引
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=20
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=30 AND sex='m';
EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE sex='m';

索引的創建會加快數據的查詢速度 但是一定程度會拖慢數據的插入和刪除速度。


免責聲明!

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



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