<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
索引對有一定開發經驗的同學來說並不陌生,合理使用索引,能大大提升sql查詢的效能,可以這麼講,隨著業務資料量的不斷增長,優化系統的響應速度,很大程度上可以說就是集中在索引的優化上;
在正式瞭解與學習mysql索引之前,先對mysql的索引原理再次回顧下;
我們知道,目前大多數使用的mysql引擎為 innodb,而innodb引擎使用的是 B+ Tree,下面通過幾張圖快速瞭解下 B+ Tree的結構,
假如存在下面這張表:
那麼通過 B+ Tree構建出來的 “ 以ID為主鍵索引 ” 的樹形結構如下:
說明:
也就是說,如果查詢的時候,以ID為引數,則效率是最高的,反之,如果以非主鍵欄位,建立索引,則B+Tree的索引結構將會如下,
說明:
以上關於mysql 的inndb的索引結構原理先介紹到這兒,後文中將會用到裡面的東西,還請留意;
MySQL的索引包括普通索引、唯一性索引、全文索引、單列索引、多列索引和空間索引等;
常規分類
補充說明
不同的儲存引擎支援的索引型別也不一樣
資料準備,有如下建表sql
CREATE TABLE `user` ( `user_id` VARCHAR (32) NOT NULL COMMENT '使用者ID', `user_name` VARCHAR (64) DEFAULT NULL COMMENT '使用者姓名', `passwd` VARCHAR (64) NOT NULL COMMENT '密碼', `email` VARCHAR (64) DEFAULT NULL COMMENT '郵箱', `mobile` VARCHAR (32) DEFAULT NULL COMMENT '手機號', `address` VARCHAR (128) DEFAULT NULL COMMENT '地址', `ID` VARCHAR (18) DEFAULT NULL COMMENT '身份證號', `sex` INT (11) DEFAULT NULL COMMENT '使用者性別 1:男 2:女', PRIMARY KEY (`user_id`) ) ENGINE = INNODB DEFAULT CHARSET = utf8;
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name ON table_name (col_name[length],...) [ASC | DESC]
比如給上表的user_name建立一個唯一索引
CREATE UNIQUE INDEX user_name_idx on `user`(user_name);
SHOW INDEX FROM table_name;
DROP INDEX index_name ON table_name;
刪除上面的表建立的唯一索引:
create index name_passwd_index on `user`(user_name, passwd);
ALTER TABLE `user` ADD FULLTEXT ( `info` );
全文索參照match+against方式查詢:
SELECT * FROM `user` WHERE MATCH(欄位名稱) AGAINST (‘查詢字串');
注意點:
使用全文索引前,搞清楚版本支援情況,不同的版本可能對全文索引支援不一樣;全文索引比 like + % 快 N 倍,但是可能存在精度問題;如果需要全文索引的是大量資料,建議先新增資料,再建立索引;
現實中,如果之前已經給表建立過相關的索引,現在需要修改或刪除,或重新建立,該如何做呢?
ALTER TABLE table_name ADD [UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [index_name] (col_name[length],…) [ASC | DESC]
比如給 user表的mobile欄位新增索引
ALTER TABLE `user` ADD INDEX `idx_mobile` (`mobile`);
ALTER TABLE table_name DROP INDEX index_name;
或者直接使用drop語句
DROP INDEX index_name ON table_name;
說明
刪除表中的列時,如果要刪除的列為索引的組成部分,則該列也會從索引中刪除。如果組成索引的所有列都被刪除,則整個索引將被刪除;
在實際開發中,索引並不是越多越好,建立索引需結合業務情況進行綜合考量,下面結合實際經驗列舉出一些常用的索引設計原則,作為建立索引時的參考;
1、欄位值在業務中具備唯一性
業務上具有唯一特性的欄位,即使是組合欄位,也必須建成唯一索引,比如使用者表中,可以通過身份證號或微訊號作為 唯一索引;
2、頻繁作為 WHERE 查詢條件的欄位
某欄位在SELECT語句WHERE 條件中頻繁使用,就需要給這個欄位建立索引。尤其是資料量大時,建立索引就可以大幅提升查詢的效率;比如使用者表的 user_id
3、UPDATE、DELETE 的 WHERE 條件列
我們知道,如果更新的這個列建立了索引,在真正執行資料更新的時候,不僅要更新資料,還要更新這個列的索引資訊,在這種情況下,建議只對查詢的那個欄位建立索引(非索引欄位更新的時候速度更快);
4、經常 GROUP BY 和 ORDER BY 的列
索引是讓資料按某種順序進行儲存或檢索,因此使用 GROUP BY 對資料進行分組查詢,或者使用 ORDER BY 對資料排序的時候,就需要 對分組或者排序的欄位進行索引 。如果待排序的列有多個,那麼可以在這些列上建立 組合索引 ,以提升速度;
5、對DISTINCT 欄位建立索引
有時候需要使用DISTINCT對某欄位進行去重,那麼對這個欄位建立索引,也會提升查詢效率。這是因為索引會對資料按照某種順序進行排序,所以有了索引在去重的時候會快很多。
6、使用列的型別小的建立索引
7、使用字串字首建立索引
舉個例子來說,在user表中存在一個郵箱eamil欄位,通常來說,對於一個穩定的業務系統,user標準的email格式可以說格式上是固定的,比如 數位@qq.com,名稱@163.com等;
我們知道索引也是要佔用儲存空間的,欄位的長度越長,建立的索引最終佔用的空間也越大,當表的資料量大到一定程度,查詢時就算是檢索走索引也會花費較長時間,這時候就可以考慮使用字串字首建立索引了;
可以使用下面的語句建立字串字首建立索引:
alter table useradd index(email(6));
這裡的問題是,擷取多少呢?擷取多了,達不到節省索引儲存空間的目的;擷取少了,重複內容太多,欄位的雜湊度(選擇性)會降低。怎麼計算不同的長度的選擇性呢?下面給出一個經驗公式作為參考,
先看一下欄位在全部資料中的選擇度:
select count(distinct email) / count(*) from user;
通過不同長度去計算,與全表的選擇性對比:
count(distinct left(列名, 索引長度))/count(*)
8、使用最頻繁的列放到聯合索引的左側
這樣可以儘可能的向查詢時的最佳左字首原則靠攏;
9、在多欄位都要建立索引的情況下,聯合索引優於單值索引
試想當user表中,當user_name,mobile都需要建立索引時,分別建立兩個單列索引帶來的開銷,與建立一個聯合索引帶來的開銷哪個更大呢?
10、 區分度高(雜湊性高)的列適合作為索引
如果表中存在性別這樣的欄位,就不太適合建立索引,這個需要注意;
11、多表 JOIN 時,建立索引注意事項
12、有大量重複資料的列上不要建立索引
在這樣的列上一旦建立了索引,比如表中有50萬資料,你需要先存取 50 萬次索引,然後再存取 50 萬次資料表,這樣加起來的開銷比不使用索引可能還要大;
一個經驗值
當資料重複度大,比如高於 10% 的時候,就不需要對這個欄位建立索引;
13、避免對經常更新的表建立過多索引
這個算是常識性的經驗了,更新資料時候,不經要更新資料本身,還需要更新索引;
14、不建議用無序的值作為索引
例如身份證、UUID(在索引比較時需要轉為ASCII,並且插入時可能造成頁分裂)、MD5、HASH、無序長字串等;
15、不要定義冗餘或重複的索引
即對同一個欄位而言,不要建立多個不同名稱的索引,這樣只會增加維護的成本,並不會對搜尋有什麼好處;
16、及時刪除不再使用或者很少使用的索引
減少索引儲存空間對整個表空間的開銷
1、不要在索引列上進行操作計算
計算、函數、型別轉換(自動或手動)導致索引失效,上面的user表中,我們給phone建立了索引,但如果使用下面的函數進行查詢,索引將會失效;
explain select * from `user` where SUBSTRING(mobile,10,2) = '12'
2、字串查詢時一定要加引號
字串查詢不加引號時存在隱式轉換,將會使索引失效
3、模糊匹配
如果僅僅是尾部的模糊匹配,仍然會走索引(即後like);但如果是頭部匹配,索引將會失效;
like在前
like在後
前後都有like
很多同學在實際開發中,習慣性的就寫上前後都帶有 like的語句,而在表資料量越來越大的情況下,效率將會非常低;
4、使用 or 連線的條件
用or分開的欄位作為條件查詢時,如果or前面的列有索引,但是後面的列沒有索引,那麼整條查詢將不會使用到索引;
explain select * from `user` where mobile = '13366767812' or email = '16678623@qq.com'
usr表中,email由於沒有建索引,所以or 的查詢結果中,最終沒有用到索引;
5、範圍條件右邊的列索引失效
對於某些聯合索引,如果用到了範圍查詢但是查詢條件的欄位未按照聯合索引的欄位順序,將會使得索引失效;
如下,user_name 和age建立了聯合索引,使用下面這條sql分析可知
explain select * from `user` where age > 25 and user_name = '張小華'
在這種情況下,需要將範圍查詢條件放置語句最後;
6、不等於(!= 或者<>)索引失效
儘量避免在巨量資料量的查詢中使用 != 這種查詢
7、 is null可以使用索引,is not null無法使用索引
CREATE index idx_mobile on `user`(mobile)
分別使用下面的sql進行分析
8、使用 not in和not exists 這樣的關鍵字導致索引失效
9、不合理的使用order by導致索引失效
其實,這個也很好理解,畢竟需要對全表資料進行排序處理,在網路上看到有說如果order by條件滿足最左匹配則會正常走索引, 在當前8.0.18版本中並未出現。所以,在基於order by和limit進行使用時,要特別留意。是否走索引不僅涉及到資料庫版本,還要看Mysql優化器是如何處理的。
但是使用主鍵進行排序,則是可以走索引的,這一點需要注意
10、其他情況
當然,還有其他一些是否走索引的規則,這與索引的型別是B-tree索引還是點陣圖索引也有關係;
這裡要說的其他,可以總結為:
Mysql優化器的其他優化策略,比如優化器認為在某些情況下,全表掃描比走索引快,則它就會放棄索引;針對這種情況,一般不用過多理會,當發現問題時再定點排查即可
最後,補充一個知識點,即使用覆蓋索引
即查詢要返回的結果欄位中,儘可能的在索引中使用到(或全部用到),減少使用 "select * " 這樣的查詢;
比如下面這條語句
select address,age from `user` where user_id = '1'
儘管使用到了主鍵查詢,但是查詢的欄位 address 和 age並未包含在索引列中,所以這種情況下,innodb引擎最終需要通過回表的方式才能將資料的結果查出來;
還記得本文開頭的這張圖吧
當我們查詢一條記錄時,使用的條件為 name = ‘名字’,儘管對name建立了索引,但是name的索引結構中,其葉子節點儲存的是name值以及id值,假如這時,你的查詢語句中需要返回的欄位不是id和name,而是address和mobile,這時,就需要拿到id再次去查詢,一直查到id的索引樹下的完整的記錄,這就是所謂的回表;
當表的資料量足夠大的時候,回表耗費的時間是很長的,這個對整體的查詢響應來說一定會成為一個需要優化的點;
到此這篇關於mysql 索引使用及優化詳情的文章就介紹到這了,更多相關mysql 索引優化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45