关于索引的相关 day45
mysql數據庫索引相關
一 介紹
什么是索引?
索引在MySQL中也叫做“鍵”,是存儲引擎用于快速找到記錄的一種數據結構。索引對于良好的性能
非常關鍵,尤其是當表中的數據量越來越大時,索引對于性能的影響愈發重要。
索引優化應該是對查詢性能優化最有效的手段了。索引能夠輕易將查詢性能提高好幾個數量級。
索引相當于字典的音序表,如果要查某個字,如果不使用音序表,則需要從幾百頁中逐頁去查。
(建索引是讓mysql提供的一種數據結構)
索引相關見解
索引是應用程序設計和開發的一個重要方面。若索引太多,應用程序的性能可能會受到影響。而索引太少,對查詢性能又會產生影響,要找到一個平衡點,這對應用程序的性能至關重要。一些開發人員總是在事后才想起添加索引----我一直認為,這源于一種錯誤的開發模式。如果知道數據的使用,從一開始就應該在需要處添加索引。開發人員往往對數據庫的使用停留在應用的層面,比如編寫SQL語句、存儲過程之類,他們甚至可能不知道索引的存在,或認為事后讓相關DBA加上即可。DBA往往不夠了解業務的數據流,而添加索引需要通過監控大量的SQL語句進而從中找到問題,這個步驟所需的時間肯定是遠大于初始添加索引所需的時間,并且可能會遺漏一部分的索引。當然索引也并不是越多越好,我曾經遇到過這樣一個問題:某臺MySQL服務器iostat顯示磁盤使用率一直處于100%,經過分析后發現是由于開發人員添加了太多的索引,在刪除一些不必要的索引之后,磁盤使用率馬上下降為20%。可見索引的添加也是非常有技術含量的。
二、索引的原理
索引的目的在于提高查詢效率。
本質:通過不斷的縮小想要獲取數據的范圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是,有了這種索引機制,我們可以總是用同一種查找方式來鎖定數據。
三、 索引的數據結構
需要這種數據結構能夠做些什么,其實很簡單,那就是:每次查找數據時把磁盤IO次數控制在一個很小的數量級,最好是常數數量級。那么我們就想到如果一個高度可控的多路搜索樹是否能滿足需求呢?就這樣,b+樹應運而生(B+樹是通過二叉查找樹,再由平衡二叉樹,B樹演化而來)。
如上圖,是一顆b+樹,關于b+樹的定義可以參見B+樹,這里只說一些重點,淺藍色的塊我們稱之為一個磁盤塊,可以看到每個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),如磁盤塊1包含數據項17和35,包含指針P1、P2、P3,P1表示小于17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大于35的磁盤塊。真實的數據存在于葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點只不存儲真實的數據,只存儲指引搜索方向的數據項,如17、35并不真實存在于數據表中。
b+樹性質
1、索引字段要盡量的小
2、索引的最左匹配特性
三、常見的索引
索引分類:
1、普通索引INDEX:加速查找
唯一索引:
2、-主鍵索引PRIMARY KEY:加速查找+約束(不為空、不能重復)
3、-唯一索引UNIQUE:加速查找+約束(不能重復)
4、-組合索引
組合索引是將n個列組合成一個索引
5、聯合索引:
??? -PRIMARY KEY(id,name):聯合主鍵索引
??? -UNIQUE(id,name):聯合唯一索引
??? -INDEX(id,name):聯合普通索引
除此之外還有全文索引,即FULLTEXT,但其實對于全文搜索,我們并不會使用MySQL自帶的該索引,而是會選擇第三方軟件如Sphinx,專門來做全文搜索。
二、索引類型
索引主要包括hash和btree兩大類型,我們在創建索引時可以為其指定索引類型。其中hash類型的索引:查詢單條快,范圍查詢慢;btree類型的索引:b+樹,層數越多,數據量指數級增長(我們就用它,因為innodb默認支持它)
#不同的存儲引擎支持的索引類型也不一樣 InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引; MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引; Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引; NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 B-tree、Full-text 等索引; Archive 不支持事務,支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引;三、創建與刪除索引
1、在創建表時創建索引
create table t1(??? id int,
??? name char(5),
??? age int,
??? unique key uni_name(name),??? # uni_name 為索引名 ??? ?
??? index index_age(age),???????? # index_age 為索引名,不需要key
??? primary key(id)?????????????? # primary 不需要起索引名,起了也不顯示 ?? ?
???? );
2、創建完表后為其添加索引
3、刪除索引
?
drop index indx_id on t3;alter table t3 drop primary key;上述第一個刪除語法中,因primary key 沒有名字,所以刪除方式為:drop index ‘primary’ on t3,其他有名字的索引刪除方式為:drop index 索引名 on 表名
?
四、測試索引
按照如下sql語句創建表s1,后續所有測試均基于此表:
#1. 準備表 create table s1( id int, name varchar(20), gender char(6), email varchar(50) );#2. 創建存儲過程,實現批量插入記錄 delimiter $$ #聲明存儲過程的結束符號為$$ create procedure auto_insert1() BEGINdeclare i int default 1;while(i<3000000)doinsert into s1 values(i,'egon','male',concat('egon',i,'@oldboy'));set i=i+1;end while; END$$ #$$結束 delimiter ; #重新聲明分號為結束符號#3. 查看存儲過程 show create procedure auto_insert1\G #4. 調用存儲過程 call auto_insert1();1、加索引可以加快查詢效率,但是會降低寫的效率
?五、正確使用索引
但我們必須知道,并不是說我們創建了索引就一定會加快查詢速度,若想利用索引達到預想的提高查詢速度的效果,我們在添加索引時,必須遵循以下問題。
1、范圍問題,或者說條件不明確,條件中出現這些符號或關鍵字:>、>=、<、<=、!= 、between...and...、like
大于 小于
?
不等于
between...and
?
?like
?
?2、盡量選擇區分度高的字段作為索引,區分度是指的字段中數據的重復性,越重復,區分度變低
?
我們編寫存儲過程為表s1批量添加記錄,name字段的值均為egon,也就是說name這個字段的區分度很低(gender字段也是一樣的,我們稍后再搭理它)回憶b+樹的結構,查詢的速度與樹的高度成反比,要想將樹的高低控制的很低,需要保證:在某一層內數據項均是按照從左到右,從小到大的順序依次排開,即左1<左2<左3<...而對于區分度低的字段,無法找到大小關系,因為值都是相等的,毫無疑問,還想要用b+樹存放這些等值的數據,只能增加樹的高度,字段的區分度越低,則樹的高度越高。極端的情況,索引字段的值都一樣,那么b+樹幾乎成了一根棍。本例中就是這種極端的情況,name字段所有的值均為'egon'#現在我們得出一個結論:為區分度低的字段建立索引,索引樹的高度會很高,然而這具體會帶來什么影響呢???#1:如果條件是name='xxxx',那么肯定是可以第一時間判斷出'xxxx'是不在索引樹中的(因為樹中所有的值均為'egon’),所以查詢速度很快#2:如果條件正好是name='egon',查詢時,我們永遠無法從樹的某個位置得到一個明確的范圍,只能往下找,往下找,往下找。。。這與全表掃描的IO次數沒有多大區別,所以速度很慢
?
3、索引字段不可以參與計算
?\
?
?
??在左邊條件成立但是索引字段的區分度低的情況下(name與gender均屬于這種情況),會依次往右找到一個區分度高的索引字段,加速查詢
?
?
??在左邊條件成立但是索引字段的區分度低的情況下(name與gender均屬于這種情況),會依次往右找到一個區分度高的索引字段,加速查詢
?經過分析,在條件為name='egon' and gender='male' and id>333 and email='xxx'的情況下,我們完全沒必要為前三個條件的字段加索引,因為只能用上email字段的索引,前三個字段的索引反而會降低我們的查詢效率。
?5、最左前綴匹配原則,非常重要的原則,對于組合索引mysql會一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配(指的是范圍大了,有索引速度也慢),比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。
6、其他情況
- 使用函數select * from tb1 where reverse(email) = 'egon';- 類型不一致如果列是字符串類型,傳入條件是必須用引號引起來,不然...select * from tb1 where email = 999;#排序條件為索引,則select字段必須也是索引字段,否則無法命中 - order byselect name from s1 order by email desc;當根據索引排序時候,select查詢的字段如果不是索引,則速度仍然很慢select email from s1 order by email desc;特別的:如果對主鍵排序,則還是速度很快:select * from tb1 order by nid desc;- 組合索引最左前綴如果組合索引為:(name,email)name and email -- 命中索引name -- 命中索引email -- 未命中索引- count(1)或count(列)代替count(*)在mysql中沒有差別了- create index xxxx on tb(title(19)) #text類型,必須制定長度 - 避免使用select * - count(1)或count(列) 代替 count(*) - 創建表時盡量時 char 代替 varchar - 表的字段順序固定長度的字段優先 - 組合索引代替多個單列索引(經常使用多個條件查詢時) - 盡量使用短索引 - 使用連接(JOIN)來代替子查詢(Sub-Queries) - 連表時注意條件類型需一致 - 索引散列值(重復少)不適合建索引,例:性別不適合六、索引合并與覆蓋
1、索引合并
#覆蓋索引:- 所有字段(條件的,查詢結果的等)都是索引字段http://blog.itpub.net/22664653/viewspace-774667/#分析 select age from s1 where id=123 and name = 'egon'; #id字段有索引,但是name字段沒有索引 該sql命中了索引,但未覆蓋全部。 利用id=123到索引的數據結構中定位到了id字段,但是仍要判斷name字段,但是name字段沒有索引,而且查詢結果的字段age也沒有索引 最牛逼的情況是,索引字段覆蓋了所有,那全程通過索引來加速查詢以及獲取結果就ok了七、查詢優化神器explain
關于explain命令相信大家并不陌生,具體用法和字段含義可以參考官網explain-output,這里需要強調rows是核心指標,絕大部分rows小的語句執行一定很快(有例外,下面會講到)。所以優化語句基本上都是在優化rows。
轉載于:https://www.cnblogs.com/xiaoluoboer/p/8075911.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的关于索引的相关 day45的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++ winpcap开发(3)
- 下一篇: 个人总结04