本文口味:番茄炒蛋,預計閱讀:10分鐘。java
博客又停更了兩個月,在這期間,對人生和世界多了許多思考。在人生的不一樣階段,會對生活和世界有着不同的認知,而認知的改變也會直接反應在行爲模式之中。mysql
對於生活的思考心得也會在以後的時間裏,慢慢分享給你們,一方面是對本身心路歷程的記錄和總結,另外一方面也但願能給遇到一樣問題或疑惑的朋友以幫助。目前生活已經慢慢調整到我想要的樣子,博客寫做也該繼續起航了。sql
Mysql是最經常使用的關係型數據庫,而索引則是Mysql調優中最關心的部分,設計一個好的索引並寫出合適的sql,就能將查詢速度大大提高。從本篇開始,將會對Mysql中的索引進行深刻淺出的介紹,從索引的簡介、類別、使用姿式到索引的原理,最後到索引實戰。但願經過本系列的文章,能讓你對mysql中的索引有一個更深刻的認識。數據庫
如下是本文大綱:數據結構
索引是存儲引擎用於快速查找記錄的一種數據結構。app
emm,用人話說,若是把Mysql比做一本書的話,索引就是書的目錄,根據目錄便能很快找到須要的信息所在的頁面,若是沒有目錄的話,想要查找想要的信息就只能一頁一頁翻了。
好比下面這樣一條簡單的sql:cors
SELECT id,name,course,grade FROM t_grade WHERE name = 'Frank';
若是沒有添加索引的話,只能從最小記錄開始依次遍歷mysql中的記錄,而後對比每條記錄是否符合搜索條件。若是表中的數據量不大(十萬級別如下),耗時其實也還好,畢竟目前來講,CPU效率已經很高了。但這樣實際上是對CPU的一種浪費,就比如開着跑車在泥濘的鄉村小路上駕駛,徹底沒法發揮它應有的性能。而索引即是這樣一條康莊大道,有了索引,才能充分發揮mysql引擎的性能,讓你的sql跑車風馳電掣。dom
對於大部分事物而言,一般存在其對立面的,有好的一面,就會有壞的一面,就像質量好的東西一般價格高,便宜的東西一般質量差,索引也是如此。性能
使用索引的優勢顯而易見:測試
總而言之,用一個字來總結,就是快。
使用索引的缺點也是須要考慮的:
因此使用索引並非百利而無一害,使用不當甚至可能形成刪庫跑路的慘劇【手動滑稽】。但當你瞭解它的原理,掌握了索引的真諦,它就會成爲你的神兵利器,讓你在mysql開發中所向披靡。
索引可分爲普通索引、惟一索引、主鍵索引、組合索引、全文索引。看起來好像不少很複雜,但其實並不是如此,且聽我慢慢道來。
普通索引
,名字中就透露出它普通的氣質,也就是最多見的索引。
如何建立一個普通索引呢?其實很簡單,若是是在DDL中建立索引,能夠這樣使用:
CREATE TABLE `t_grade` ( id BIGINT(20) COMMENT '主鍵id', name VARCHAR(30) COMMENT '姓名', course INT COMMENT '課程,1-語文,2-數學,3-英語,4-物理', grade DECIMAL(5,2) COMMENT '成績', KEY idx_name(`name`) )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
這樣就爲"name"列建立了一個名爲"idx_name"的普通索引。通用的建立方式爲:
KEY 索引名 (`列名`)
若是是爲一張已經建立好的表添加一個普通索引,那麼能夠這樣:
ALTER TABLE `t_grade` ADD KEY idx_name(`name`);
你可能會說,「不是用index關鍵字來建立索引的嗎」,別急別急,其實它們的效果是同樣的。
主鍵索引
,一看就是很關鍵的角色,沒錯,每張表都會有且只有一個主鍵索引,即便沒有顯式的建立主鍵索引的話,也會自動建立一個隱藏的主鍵索引。
這麼重要的索引,用的關鍵字確定也得不同才行,建立主鍵索引的關鍵字是PRIMARY KEY
,在DDL中添加主鍵索引的姿式爲:
CREATE TABLE `t_grade` ( id BIGINT(20) COMMENT '主鍵id', name VARCHAR(30) COMMENT '姓名', course INT COMMENT '課程,1-語文,2-數學,3-英語,4-物理', grade DECIMAL(5,2) COMMENT '成績', PRIMARY KEY (`id`) )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
由於主鍵只能有一個,因此不須要添加主鍵名。通用的添加方式爲:
PRIMARY KEY (`列名`)
若是是爲已建立好的表添加主鍵索引,那麼能夠這樣:
ALTER TABLE `t_grade` ADD PRIMARY KEY (`id`);
惟一索引
,顧名思義,就是「惟一」的索引,被添加到索引中的列的值必須是惟一的,若是向數據表中插入一條已存在的惟一索引字段記錄,就會報錯。
定義惟一索引的關鍵字爲 UNIQUE KEY
。在DDL中添加惟一索引的姿式爲:
CREATE TABLE `t_grade` ( id BIGINT(20) COMMENT '主鍵id', name VARCHAR(30) COMMENT '姓名', course INT COMMENT '課程,1-語文,2-數學,3-英語,4-物理', grade DECIMAL(5,2) COMMENT '成績', UNIQUE KEY uk_name (`name`) )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
惟一索引的通用添加方式爲:
UNIQUE KEY 索引名 (`列名`)
爲已建立好的表添加惟一索引:
ALTER TABLE `t_grade` ADD UNIQUE KEY uk_name (`name`);
組合索引
,又叫聯合索引,即是將兩個或者多個字段組合在一塊兒的索引,好像跟沒說同樣= =
看一個栗子就知道了。
CREATE TABLE `t_grade` ( id BIGINT(20) COMMENT '主鍵id', name VARCHAR(30) COMMENT '姓名', course INT COMMENT '課程,1-語文,2-數學,3-英語,4-物理', grade DECIMAL(5,2) COMMENT '成績', KEY idx_name_corse (`name`,`course`) )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
一樣是使用key
關鍵字,在索引名後添加多個字段名便可。這裏有一點須要注意的是,字段排列是有順序的。舉例說明,下面這兩個索引是不同的:
ALTER TABLE `t_grade` ADD KEY idx_name_course (`name`,`course`); ALTER TABLE `t_grade` ADD KEY idx_name_course (`course`,`name`);
索引的匹配遵循「左綴匹配原則」,舉個栗子說明,若是建立的組合索引是
ALTER TABLE `t_grade` ADD KEY idx_name_course (`name`,`course`);
那麼下面語句將能命中這個組合索引。
SELECT * FROM `t_grade` WHERE name = 'Frank';
而下面這個語句將沒法命中索引:
SELECT * FROM `t_grade` WHERE course = 1;
由於在組合索引中,索引中的記錄是先按照前一個字段排序,而後再根據後一個字段排序的,因此若是直接使用組合索引中的第二個字段查詢時,查詢索引對索引記錄進行遍歷,遍歷完成以後還須要回溯到聚簇索引中獲取完整記錄,這樣反而更耗時間,因此sql優化器會選擇直接對記錄進行遍歷。
若是你還不清楚索引的結構以及聚簇索引是什麼,不要着急,後面的文章裏會有詳細的介紹。
聯合惟一索引
,即是將多個字段組合起來造成一個惟一鍵,舉個栗子:
先刪除全部索引,而後添加兩條記錄:
INSERT INTO `t_grade` (`id`, `name`, `course`, `grade`) VALUES(1, 'Frank', 1, 100); INSERT INTO `t_grade` (`id`, `name`, `course`, `grade`) VALUES(2, 'Frank', 1, 95);
這樣就能插入兩條記錄了。
而後刪掉這兩條記錄,建立一個聯合惟一索引:
ALTER TABLE `t_grade` ADD UNIQUE KEY idx_name_course (`name`,`course`);
而後再來執行一下上面的sql:
這時候,就會獲得一個錯誤提示,由於將字段name
和course
建立了聯合惟一索引,因此這兩個字段的組合值必須是惟一的,若是要插入的記錄的這兩個字段組合值已經存在,那麼就會拋出異常。
最後一個是比較複雜的索引:全文索引
,因爲其複雜性,這裏只簡單的介紹它的建立姿式。
CREATE TABLE `t_article`( id BIGINT COMMENT '文章id', title VARCHAR(200) COMMENT '文章標題', content TEXT COMMENT '文章內容', FULLTEXT (title, content) )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
或者給現有表添加全文索引:
ALTER TABLE `t_article` ADD FULLTEXT KEY fidx_title_content (title,content) WITH PARSER ngram;
想要使用全文索引查詢,則須要使用MATCH關鍵字。
SELECT * FROM `t_article` WHERE MATCH(title, content) AGAINST('查詢字符串');
固然,若是想要使用全文索引,須要確認mysql的版本號在5.7以上,不然沒法在innodb引擎上使用全文索引的中文檢索插件ngram。
爲了更直觀的看出索引的優缺點,咱們能夠來對數據表添加索引先後執行相同sql的耗時來看出對比,這裏僅進行簡單的比較,沒有使用性能測試。
先來建立一個數據表:
CREATE TABLE `t_grade` ( id BIGINT(20) COMMENT '主鍵id', name VARCHAR(30) COMMENT '姓名', course INT COMMENT '課程,0-化學,1-語文,2-數學,3-英語,4-物理', grade DECIMAL(5,2) COMMENT '成績' )ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
而後插入一百萬條數據:
public void batchInsert(){ long timeMillis = System.currentTimeMillis(); System.out.println("開始插入數據"); for (int i = 1; i < 1000000; i++) { GradeDO gradeDO = new GradeDO((long) i, randomName(), random.nextInt(5), BigDecimal.valueOf(random.nextDouble() * 100)); gradeMapper.insert(gradeDO); } System.out.println("插入一百萬條記錄耗時:" + ( System.currentTimeMillis() - timeMillis) / 1000.0 ); }
輸出以下:
開始插入數據 插入一百萬條記錄耗時:1507.102
如今是沒有索引的狀態,開始進行插入測試:
public void batchInsert(){ long timeMillis = System.currentTimeMillis(); System.out.println("開始插入數據"); for (int i = 1000000; i < 1010000; i++) { GradeDO gradeDO = new GradeDO((long) i, randomName(), random.nextInt(5), BigDecimal.valueOf(random.nextDouble() * 100)); gradeMapper.insert(gradeDO); } System.out.println("插入一萬條記錄耗時:" + ( System.currentTimeMillis() - timeMillis) / 1000.0 ); }
輸出以下:
開始插入數據 插入一萬條記錄耗時:15.681
而後進行查詢測試。
@Test void testQuery() { long timeMillis = System.currentTimeMillis(); System.out.println("開始查詢"); for (int i = 0; i < 100; i++) { Integer id = random.nextInt(1000000); GradeDO gradeDO = gradeMapper.selectById(id); } System.out.println("一百次查詢耗時:" + ( System.currentTimeMillis() - timeMillis) / 1000.0 ); }
輸出以下:
開始查詢 一百次查詢耗時:51.658
接下來,爲id列建立一個主鍵,併爲name字段建立一個普通索引。
再插入一萬條記錄:
開始插入數據 插入一萬條記錄耗時:17.465
而後進行查詢測試。
開始查詢 一百次查詢耗時:0.191
能夠看出,在有單個索引的狀況下,建立記錄耗時略長於無索引的狀況,當字段數量和索引數量增長時,這種差距將會增大。查詢效率能夠清晰的看出,這裏添加了索引以後,大大的縮減了查詢的耗時,固然,這裏主要是聚簇索引的功勞。
索引是mysql中十分重要的一個特性,使用好它就能讓你的sql如虎添翼。簡單來講,索引一方面能夠大大提高查詢性能,另外一方面也會佔用時間和空間成本,所以索引的選擇也是一門學問。索引有不少種類型,不一樣類型的索引有着不一樣的特性,所以只有瞭解了它們各自的特性才能正確使用它們。
關於索引的簡介就先介紹到這裏了,後面會對索引的原理進行進一步深刻的介紹,讓你不只知道怎麼使用索引,並且還能知道爲何要這樣使用索引。
若是本文對你有幫助,不要吝嗇你的點贊哦。也歡迎關注個人公衆號進行留言交流。