Mysql索引整理總結(jié)

一护侮、索引概述

1. 簡介

索引是對數(shù)據(jù)庫表中一列或多列的值進行排序的一種結(jié)構(gòu)拳氢,使用索引可快速訪問數(shù)據(jù)庫表中的特定信息践剂。

舉例說明索引:如果把數(shù)據(jù)庫中的某一張看成一本書弓摘,那么索引就像是書的目錄,可以通過目錄快速查找書中指定內(nèi)容的位置刃宵,對于數(shù)據(jù)庫表來說衡瓶,可以通過索引快速查找表中的數(shù)據(jù)。

2. 索引的原理

索引一般以文件形式存在磁盤中(也可以存于內(nèi)存中)牲证,存儲的索引的原理大致概括為以空間換時間哮针,數(shù)據(jù)庫在未添加索引的時候進行查詢默認的是進行全量搜索,也就是進行全局掃描坦袍,有多少條數(shù)據(jù)就要進行多少次查詢十厢,然后找到相匹配的數(shù)據(jù)就把他放到結(jié)果集中,直到全表掃描完捂齐。而建立索引之后蛮放,會將建立索引的KEY值放在一個n叉樹上(BTree)。因為B樹的特點就是適合在磁盤等直接存儲設(shè)備上組織動態(tài)查找表奠宜,每次以索引進行條件查詢時包颁,會去樹上根據(jù)key值直接進行搜索瞻想。

3. 索引的優(yōu)點

建立索引的目的是加快對表中記錄的查找或排序!

① 建立索引的列可以保證行的唯一性娩嚼,生成唯一的rowId

② 建立索引可以有效縮短數(shù)據(jù)的檢索時間

③ 建立索引可以加快表與表之間的連接

④ 為用來排序或者是分組的字段添加索引可以加快分組和排序順序

4. 索引的缺點

① 創(chuàng)建索引和維護索引需要時間成本蘑险,這個成本隨著數(shù)據(jù)量的增加而加大

② 創(chuàng)建索引和維護索引需要空間成本,每一條索引都要占據(jù)數(shù)據(jù)庫的物理存儲空間待锈,數(shù)據(jù)量越大漠其,占用空間也越大(數(shù)據(jù)表占據(jù)的是數(shù)據(jù)庫的數(shù)據(jù)空間)

③ 會降低表的增刪改的效率嘴高,因為每次增刪改索引需要進行動態(tài)維護竿音,導(dǎo)致時間變長

二、索引的使用場景

數(shù)據(jù)庫中表的數(shù)據(jù)量較大的情況下拴驮,對于查詢響應(yīng)時間不能滿足業(yè)務(wù)需求春瞬,可以合理的使用索引提升查詢效率。

三套啤、索引的分類和創(chuàng)建和修改刪除等命令

1. 基本索引類型

① 普通索引(單列索引)

② 復(fù)合索引(組合索引)

③ 唯一索引

④ 主鍵索引

⑤ 全文索引

2. 創(chuàng)建的語句

CREATE TABLE table_name[col_name data type]
[unique|fulltext][index|key][index_name](col_name[length])[asc|desc]

  • unique|fulltext為可選參數(shù)宽气,分別表示唯一索引、全文索引

  • index和key為同義詞潜沦,兩者作用相同萄涯,用來指定創(chuàng)建索引

  • col_name為需要創(chuàng)建索引的字段列,該列必須從數(shù)據(jù)表中該定義的多個列中選擇

  • index_name指定索引的名稱唆鸡,為可選參數(shù)涝影,如果不指定,默認col_name為索引值

  • length為可選參數(shù)争占,表示索引的長度燃逻,只有字符串類型的字段才能指定索引長度

  • asc或desc指定升序或降序的索引值存儲

3. 索引的創(chuàng)建、查詢和刪除

索引的創(chuàng)建

① 普通索引(單列索引)

普通索引(單列索引):單列索引是最基本的索引臂痕,它沒有任何限制伯襟。

(1)直接創(chuàng)建索引

CREATE INDEX index_name ON table_name(col_name);

(2)修改表結(jié)構(gòu)的方式添加索引

ALTER TABLE table_name ADD INDEX index_name(col_name);

(3)創(chuàng)建表的時候同時創(chuàng)建索引

CREATE TABLE `news` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` varchar(255)  NOT NULL ,
    `content` varchar(255)  NULL ,
    `time` varchar(20) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    INDEX index_name (title(255))
)

(4)刪除索引

DROP INDEX index_name ON table_name;
或者
alter table `表名` drop index 索引名;

② 復(fù)合索引(組合索引)

復(fù)合索引:復(fù)合索引是在多個字段上創(chuàng)建的索引。復(fù)合索引遵守“最左前綴”原則握童,即在查詢條件中使用了復(fù)合索引的第一個字段姆怪,索引才會被使用。因此澡绩,在復(fù)合索引中索引列的順序至關(guān)重要稽揭。

(1)創(chuàng)建一個復(fù)合索引

create index index_name on table_name(col_name1,col_name2,...);

(2)修改表結(jié)構(gòu)的方式添加索引

alter table table_name add index index_name(col_name,col_name2,...);

③ 唯一索引

唯一索引:唯一索引和普通索引類似,主要的區(qū)別在于英古,唯一索引限制列的值必須唯一淀衣,但允許存在空值(只允許存在一條空值)

如果在已經(jīng)有數(shù)據(jù)的表上添加唯一性索引的話:

  • 如果添加索引的列的值存在兩個或者兩個以上的空值召调,則不能創(chuàng)建唯一性索引會失敗膨桥。(一般在創(chuàng)建表的時候蛮浑,要對自動設(shè)置唯一性索引,需要在字段上加上 not null)
  • 如果添加索引的列的值存在兩個或者兩個以上的null值只嚣,還是可以創(chuàng)建唯一性索引沮稚,只是后面創(chuàng)建的數(shù)據(jù)不能再插入null值 ,并且嚴格意義上此列并不是唯一的册舞,因為存在多個null值蕴掏。

對于多個字段創(chuàng)建唯一索引規(guī)定列值的組合必須唯一。
比如:在order表創(chuàng)建orderId字段和 productId字段 的唯一性索引调鲸,那么這兩列的組合值必須唯一盛杰!


“空值” 和”NULL”的概念: 
1:空值是不占用空間的 .
2: MySQL中的NULL其實是占用空間的.

長度驗證:注意空值的之間是沒有空格的。

> select length(''),length(null),length(' ');
+------------+--------------+-------------+
| length('') | length(null) | length(' ') |
+------------+--------------+-------------+
|          0 |         NULL |           1 |
+------------+--------------+-------------+

(1)創(chuàng)建唯一索引

# 創(chuàng)建單個索引
CREATE UNIQUE INDEX index_name ON table_name(col_name);

# 創(chuàng)建多個索引
CREATE UNIQUE INDEX index_name on table_name(col_name,...);

(2)修改表結(jié)構(gòu)

# 單個
ALTER TABLE table_name ADD UNIQUE index index_name(col_name);
# 多個
ALTER TABLE table_name ADD UNIQUE index index_name(col_name,...);

(3)創(chuàng)建表的時候直接指定索引

CREATE TABLE `news` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` varchar(255)  NOT NULL ,
    `content` varchar(255)  NULL ,
    `time` varchar(20) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    UNIQUE index_name_unique(title)
)

④ 主鍵索引

主鍵索引是一種特殊的唯一索引藐石,一個表只能有一個主鍵即供,不允許有空值。一般是在建表的時候同時創(chuàng)建主鍵索引:

(1)主鍵索引(創(chuàng)建表時添加)


CREATE TABLE `news` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` varchar(255)  NOT NULL ,
    `content` varchar(255)  NULL ,
    `time` varchar(20) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`)
)

(2)主鍵索引(創(chuàng)建表后添加)

alter table tbl_name add primary key(col_name);

CREATE TABLE `order` (
    `orderId` varchar(36) NOT NULL,
    `productId` varchar(36)  NOT NULL ,
    `time` varchar(20) NULL DEFAULT NULL
)

alter table `order` add primary key(`orderId`);

⑤ 全文索引

在一般情況下于微,模糊查詢都是通過 like 的方式進行查詢逗嫡。但是,對于海量數(shù)據(jù)株依,這并不是一個好辦法驱证,在 like "value%" 可以使用索引,但是對于 like "%value%" 這樣的方式恋腕,執(zhí)行全表查詢抹锄,這在數(shù)據(jù)量小的表,不存在性能問題吗坚,但是對于海量數(shù)據(jù)祈远,全表掃描是非常可怕的事情,所以 like 進行模糊匹配性能很差商源。

這種情況下车份,需要考慮使用全文搜索的方式進行優(yōu)化。全文搜索在 MySQL 中是一個 FULLTEXT 類型索引牡彻。FULLTEXT 索引在 MySQL 5.6 版本之后支持 InnoDB扫沼,而之前的版本只支持 MyISAM 表

全文索引主要用來查找文本中的關(guān)鍵字庄吼,而不是直接與索引中的值相比較缎除。fulltext索引跟其它索引大不相同,它更像是一個搜索引擎总寻,而不是簡單的where語句的參數(shù)匹配器罐。fulltext索引配合match against操作使用,而不是一般的where語句加like渐行。目前只有char轰坊、varchar铸董,text 列上可以創(chuàng)建全文索引。

小技巧:
在數(shù)據(jù)量較大時候肴沫,先將數(shù)據(jù)放入一個沒有全局索引的表中粟害,然后再用CREATE index創(chuàng)建fulltext索引,要比先為一張表建立fulltext然后再將數(shù)據(jù)寫入的速度快很多颤芬。

(1)創(chuàng)建表的適合添加全文索引

CREATE TABLE `news` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` varchar(255)  NOT NULL ,
    `content` text  NOT NULL ,
    `time` varchar(20) NULL DEFAULT NULL ,
     PRIMARY KEY (`id`),
    FULLTEXT (content)
)

(2)修改表結(jié)構(gòu)添加全文索引

ALTER TABLE table_name ADD FULLTEXT index_fulltext_content(col_name)

(3)直接創(chuàng)建索引

CREATE FULLTEXT INDEX index_fulltext_content ON table_name(col_name)

注意: 默認 MySQL 不支持中文全文檢索悲幅!

MySQL 全文搜索只是一個臨時方案,對于全文搜索場景站蝠,更專業(yè)的做法是使用全文搜索引擎汰具,例如 ElasticSearch 或 Solr。

索引的查詢和刪除

#查看:
show indexes from `表名`;
#或
show keys from `表名`;
 
#刪除
alter table `表名` drop index 索引名;


注:MySQl的客戶端工具也可以進索引的創(chuàng)建沉衣、查詢和刪除郁副,如 Navicat Premium!

四、簡單實例演示

查看索引使用情況

show status like 'Handler_read%';

handler_read_key:這個值越高越好豌习,越高表示使用索引查詢到的次數(shù)
handler_read_rnd_next:這個值越高,說明查詢低效

常見索引失效的情況:

創(chuàng)建一個students表:
其中stud_id為主鍵拔疚!

DROP TABLE IF EXISTS `students`;
CREATE TABLE `students` (
  `stud_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `email` varchar(50) NOT NULL,
  `phone` varchar(1) NOT NULL,
  `create_date` date DEFAULT NULL,
  PRIMARY KEY (`stud_id`)
 
)

INSERT INTO `learn_mybatis`.`students` (`stud_id`, `name`, `email`, `phone`, `create_date`) VALUES ('1', 'admin', 'student1@gmail.com', '18729902095', '1983-06-25');
INSERT INTO `learn_mybatis`.`students` (`stud_id`, `name`, `email`, `phone`, `create_date`) VALUES ('2', 'root', '74298110186@qq.com', '2', '1983-12-25');
INSERT INTO `learn_mybatis`.`students` (`stud_id`, `name`, `email`, `phone`, `create_date`) VALUES ('3', '110', '7429811086@qq.com', '3dsad', '2017-04-28');

使用 explain 查看 索引是否生效肥隆!Mysql中explain用法和結(jié)果字段的含義介紹

1. 在where后使用or,導(dǎo)致索引失效(盡量少用or)

簡單實例演示:
創(chuàng)建兩個普通索引稚失,

CREATE INDEX index_name_email ON students(email);
CREATE INDEX index_name_phone ON students(phone);

使用下面查詢sql栋艳,

# 使用了索引
EXPLAIN select * from students where stud_id='1'  or phone='18729902095'
# 使用了索引
EXPLAIN select * from students where stud_id='1'  or email='742981086@qq.com'

#--------------------------

# 沒有使用索引
EXPLAIN select * from students where phone='18729902095' or email='742981086@qq.com'

# 沒有使用索引
EXPLAIN select * from students where stud_id='1'  or phone='222' or email='742981086@qq.com'


2.使用like ,like查詢是以%開頭

在1的基礎(chǔ)上句各,還是使用 index_name_email 索引吸占。

使用下面查詢sql

# 使用了index_name_email索引
EXPLAIN select * from students where email like '742981086@qq.com%'

# 沒有使用index_name_email索引,索引失效
EXPLAIN select * from students where email like '%742981086@qq.com'

# 沒有使用index_name_email索引凿宾,索引失效
EXPLAIN select * from students where email like '%742981086@qq.com%'
3.復(fù)合索引遵守“最左前綴”原則矾屯,即在查詢條件中使用了復(fù)合索引的第一個字段,索引才會被使用

刪除1的基礎(chǔ)創(chuàng)建的 index_name_email 和 index_name_phone 索引初厚。

重新創(chuàng)建一個復(fù)合索引:

create index index_email_phone on students(email,phone);

使用下面查詢sql

# 使用了 index_email_phone 索引
EXPLAIN select * from students where email='742981086@qq.com' and  phone='18729902095'

# 使用了 index_email_phone 索引
EXPLAIN select * from students where phone='18729902095' and  email='742981086@qq.com'

# 使用了 index_email_phone 索引
EXPLAIN select * from students where email='742981086@qq.com' and name='admin'

# 沒有使用index_email_phone索引件蚕,復(fù)合索引失效
EXPLAIN select * from students where phone='18729902095' and name='admin'

4. 如果列類型是字符串,那一定要在條件中將數(shù)據(jù)使用引號引用起來,否則不使用索引

給name創(chuàng)建一個索引产禾!

CREATE INDEX index_name ON students(name);

# 使用索引
EXPLAIN select * from students where name='110'

# 沒有使用索引
EXPLAIN select * from students where name=110

5. 使用in導(dǎo)致索引失效
# 使用索引
EXPLAIN select * from students where name='admin'

# 沒有使用索引
EXPLAIN SELECT * from students where name in ('admin')

6. DATE_FORMAT()格式化時間排作,格式化后的時間再去比較,可能會導(dǎo)致索引失效亚情。

刪除 students 上的創(chuàng)建的索引妄痪!重新在create_date創(chuàng)建一個索引!

CREATE INDEX index_create_date ON students(create_date);

# 使用索引
EXPLAIN SELECT * from students where create_date >= '2010-05-05'

# 沒有使用索引
EXPLAIN SELECT * from students where DATE_FORMAT(create_date,'%Y-%m-%d') >= '2010-05-05'


7. 對于order by楞件、group by 衫生、 union僧著、 distinc 中的字段出現(xiàn)在where條件中時,才會利用索引障簿!
8. 更多索引的使用注意可以參看這一篇博文:

索引使用注意規(guī)則(索引失效--存在索引但不使用索引)

五盹愚、總結(jié)

MySQL改善查詢性能改善的最好方式,就是通過數(shù)據(jù)庫中合理地使用索引站故!

一般當數(shù)據(jù)量較大的時候皆怕,遇到sql查詢性能問題,首先想到的應(yīng)該是查詢的sql時候使用了索引西篓,如果使用了索引性能還是提高不大愈腾,就要檢查索引是否使用正確,索引是否在sql查詢中生效了岂津!

如果索引生效了虱黄,并且索引的使用也是合理的,最后sql性能還是不高吮成,那就考慮重新優(yōu)化sql語句橱乱!

六、參考博文


如果您覺得這篇博文對你有幫助粱甫,請點贊或者喜歡泳叠,讓更多的人看到,謝謝茶宵!

如果帥氣(美麗)危纫、睿智(聰穎),和我一樣簡單善良的你看到本篇博文中存在問題乌庶,請指出种蝶,我虛心接受你讓我成長的批評,謝謝閱讀瞒大!
祝你今天開心愉快螃征!


歡迎訪問我的csdn博客,我們一同成長糠赦!

不管做什么会傲,只要堅持下去就會看到不一樣!在路上拙泽,不卑不亢!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淌山,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子顾瞻,更是在濱河造成了極大的恐慌泼疑,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荷荤,死亡現(xiàn)場離奇詭異退渗,居然都是意外死亡移稳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門会油,熙熙樓的掌柜王于貴愁眉苦臉地迎上來个粱,“玉大人,你說我怎么就攤上這事翻翩《夹恚” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵嫂冻,是天一觀的道長胶征。 經(jīng)常有香客問我,道長桨仿,這世上最難降的妖魔是什么睛低? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮服傍,結(jié)果婚禮上钱雷,老公的妹妹穿的比我還像新娘。我一直安慰自己伴嗡,他們只是感情好急波,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瘪校,像睡著了一般。 火紅的嫁衣襯著肌膚如雪名段。 梳的紋絲不亂的頭發(fā)上阱扬,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音伸辟,去河邊找鬼麻惶。 笑死,一個胖子當著我的面吹牛信夫,可吹牛的內(nèi)容都是我干的窃蹋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼静稻,長吁一口氣:“原來是場噩夢啊……” “哼警没!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起振湾,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤杀迹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后押搪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體树酪,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡浅碾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了续语。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垂谢。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疮茄,靈堂內(nèi)的尸體忽然破棺而出滥朱,到底是詐尸還是另有隱情,我是刑警寧澤娃豹,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布焚虱,位于F島的核電站,受9級特大地震影響懂版,放射性物質(zhì)發(fā)生泄漏鹃栽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一躯畴、第九天 我趴在偏房一處隱蔽的房頂上張望民鼓。 院中可真熱鬧,春花似錦蓬抄、人聲如沸丰嘉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饮亏。三九已至,卻和暖如春阅爽,著一層夾襖步出監(jiān)牢的瞬間路幸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工付翁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留简肴,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓百侧,卻偏偏與公主長得像砰识,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子佣渴,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容