自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入淺出MySQL索引的那些事兒

數(shù)據(jù)庫 MySQL
一般的應(yīng)用系統(tǒng),讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現(xiàn)性能問題,遇到最多的,也是最容易出問題的,還是一些復(fù)雜的查詢操作,所以查詢語句的優(yōu)化顯然是重中之重。

一.索引的作用

一般的應(yīng)用系統(tǒng),讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現(xiàn)性能問題,遇到最多的,也是最容易出問題的,還是一些復(fù)雜的查詢操作,所以查詢語句的優(yōu)化顯然是重中之重。

[[274518]]

在數(shù)據(jù)量和訪問量不大的情況下,mysql訪問是非常快的,是否加索引對訪問影響不大。但是當(dāng)數(shù)據(jù)量和訪問量劇增的時候,就會發(fā)現(xiàn)mysql變慢,甚至down掉,這就必須要考慮優(yōu)化sql了,給數(shù)據(jù)庫建立正確合理的索引,是mysql優(yōu)化的一個重要手段。

索引的目的在于提高查詢效率,可以類比字典,如果要查“mysql”這個單詞,我們肯定需要定位到m字母,然后從上往下找到y(tǒng)字母,再找到剩下的sql。如果沒有索引,那么你可能需要把所有單詞看一遍才能找到你想要的。除了詞典,生活中隨處可見索引的例子,如火車站的車次表、圖書的目錄等。它們的原理都是一樣的,通過不斷的縮小想要獲得數(shù)據(jù)的范圍來篩選出最終想要的結(jié)果,同時把隨機的事件變成順序的事件,也就是我們總是通過同一種查找方式來鎖定數(shù)據(jù)。

在創(chuàng)建索引時,需要考慮哪些列會用于 SQL 查詢,然后為這些列創(chuàng)建一個或多個索引。事實上,索引也是一種表,保存著主鍵或索引字段,以及一個能將每個記錄指向?qū)嶋H表的指針。數(shù)據(jù)庫用戶是看不到索引的,它們只是用來加速查詢的。數(shù)據(jù)庫搜索引擎使用索引來快速定位記錄。

INSERT 與 UPDATE 語句在擁有索引的表中執(zhí)行會花費更多的時間,而SELECT 語句卻會執(zhí)行得更快。這是因為,在進(jìn)行插入或更新時,數(shù)據(jù)庫也需要插入或更新索引值。

二.索引的創(chuàng)建、刪除

索引的類型:

  • UNIQUE(唯一索引):不可以出現(xiàn)相同的值,可以有NULL值
  • INDEX(普通索引):允許出現(xiàn)相同的索引內(nèi)容
  • PROMARY KEY(主鍵索引):不允許出現(xiàn)相同的值
  • fulltext index(全文索引):可以針對值中的某個單詞,但效率確實不敢恭維
  • 組合索引:實質(zhì)上是將多個字段建到一個索引里,列值的組合必須唯一

溫馨提示:根據(jù)《阿里巴巴Java開發(fā)手冊》里的mysql規(guī)約,唯一索引建議命名為uk_字段名,普通索引名則為idx_字段名。(uk_即unique key; idx_即index的簡稱)。

(1)使用ALTER TABLE語句創(chuàng)建索性

應(yīng)用于表創(chuàng)建完畢之后再添加。

  1. ALTER TABLE 表名 ADD 索引類型 (unique,primary key,fulltext,index)[索引名](字段名) 
  1. //普通索引 
  2. alter table table_name add index index_name (column_list) ; 
  3. //唯一索引 
  4. alter table table_name add unique (column_list) ; 
  5. //主鍵索引 
  6. alter table table_name add primary key (column_list) ; 

ALTER TABLE可用于創(chuàng)建普通索引、UNIQUE索引和PRIMARY KEY索引3種索引格式,table_name是要增加索引的表名,column_list指出對哪些列進(jìn)行索引,多列時各列之間用逗號分隔。索引名index_name可選,缺省時,MySQL將根據(jù)第一個索引列賦一個名稱。另外,ALTER TABLE允許在單個語句中更改多個表,因此可以同時創(chuàng)建多個索引。

(2)使用CREATE INDEX語句對表增加索引

CREATE INDEX可用于對表增加普通索引或UNIQUE索引,可用于建表時創(chuàng)建索引。

  1. CREATE INDEX index_name ON table_name(username(length)); 

如果是CHAR,VARCHAR類型,length可以小于字段實際長度;如果是BLOB和TEXT類型,必須指定 length。

  1. //只能添加這兩種索引; 
  2. CREATE INDEX index_name ON table_name (column_list) 
  3. CREATE UNIQUE INDEX index_name ON table_name (column_list) 

table_name、index_name和column_list具有與ALTER TABLE語句中相同的含義,索引名不可選。另外,不能用CREATE INDEX語句創(chuàng)建PRIMARY KEY索引。

(3)刪除索引

刪除索引可以使用ALTER TABLE或DROP INDEX語句來實現(xiàn)。DROP INDEX可以在ALTER TABLE內(nèi)部作為一條語句處理,其格式如下:

  1. drop index index_name on table_name ; 
  2.  
  3. alter table table_name drop index index_name ; 
  4.  
  5. alter table table_name drop primary key ; 

其中,在前面的兩條語句中,都刪除了table_name中的索引index_name。而在最后一條語句中,只在刪除PRIMARY KEY索引中使用,因為一個表只可能有一個PRIMARY KEY索引,因此不需要指定索引名。如果沒有創(chuàng)建PRIMARY KEY索引,但表具有一個或多個UNIQUE索引,則MySQL將刪除第一個UNIQUE索引。

如果從表中刪除某列,則索引會受影響。對于多列組合的索引,如果刪除其中的某列,則該列也會從索引中刪除。如果刪除組成索引的所有列,則整個索引將被刪除。

(4) 組合索引與前綴索引

在這里要指出,組合索引和前綴索引是對建立索引技巧的一種稱呼,并不是索引的類型。為了更好的表述清楚,建立一個demo表如下。

  1. create table USER_DEMO 
  2.    ID                   int not null auto_increment comment '主鍵'
  3.    LOGIN_NAME           varchar(100) not null comment '登錄名'
  4.    PASSWORD             varchar(100) not null comment '密碼'
  5.    CITY                 varchar(30) not null comment '城市'
  6.    AGE                  int not null comment '年齡'
  7.    SEX                  int not null comment '性別(0:女 1:男)'
  8.    primary key (ID) 
  9. ); 

為了進(jìn)一步榨取mysql的效率,就可以考慮建立組合索引,即將LOGIN_NAME,CITY,AGE建到一個索引里:

  1. ALTER TABLE USER_DEMO ADD INDEX name_city_age (LOGIN_NAME(16),CITY,AGE); 

建表時,LOGIN_NAME長度為100,這里用16,是因為一般情況下名字的長度不會超過16,這樣會加快索引查詢速度,還會減少索引文件的大小,提高INSERT,UPDATE的更新速度。

如果分別給LOGIN_NAME,CITY,AGE建立單列索引,讓該表有3個單列索引,查詢時和組合索引的效率是大不一樣的,甚至遠(yuǎn)遠(yuǎn)低于我們的組合索引。雖然此時有三個索引,但mysql只能用到其中的那個它認(rèn)為似乎是最有效率的單列索引,另外兩個是用不到的,也就是說還是一個全表掃描的過程。

建立這樣的組合索引,就相當(dāng)于分別建立如下三種組合索引:

  1. LOGIN_NAME,CITY,AGE 
  2. LOGIN_NAME,CITY 
  3. LOGIN_NAME 

為什么沒有CITY,AGE等這樣的組合索引呢?這是因為mysql組合索引“最左前綴"的結(jié)果。簡單的理解就是只從最左邊的開始組合,并不是只要包含這三列的查詢都會用到該組合索引。也就是說name_city_age(LOGIN_NAME(16),CITY,AGE)從左到右進(jìn)行索引,如果沒有左前索引,mysql不會執(zhí)行索引查詢。

如果索引列長度過長,這種列索引時將會產(chǎn)生很大的索引文件,不便于操作,可以使用前綴索引方式進(jìn)行索引,前綴索引應(yīng)該控制在一個合適的點,控制在0.31黃金值即可(大于這個值就可以創(chuàng)建)。

  1. SELECT COUNT(DISTINCT(LEFT(`title`,10)))/COUNT(*) FROM Arctic; -- 這個值大于0.31就可以創(chuàng)建前綴索引,Distinct去重復(fù)  
  2. ALTER TABLE `userADD INDEX `uname`(title(10)); -- 增加前綴索引SQL,將人名的索引建立在10,這樣可以減少索引文件大小,加快索引查詢速度 

三.索引的使用及注意事項

EXPLAIN可以幫助開發(fā)人員分析SQL問題,explain顯示了mysql如何使用索引來處理select語句以及連接表,可以幫助選擇更好的索引和寫出更優(yōu)化的查詢語句。

使用方法,在select語句前加上Explain就可以了:

  1. Explain select * from user where id=1; 

盡量避免這些不走索引的sql:

  1. SELECT name,phone FROM `userWHERE `age`+10=30; -- 不會使用索引,因為所有索引列參與了計算 
  2.  
  3. SELECT name,phone  FROM `userWHERE LEFT(`date`,4) <1990; -- 不會使用索引,因為使用了函數(shù)運算,原理與上面相同 
  4.  
  5. SELECT * FROM `userWHERE `nameLIKE'后盾%' -- 走索引 
  6.  
  7. SELECT * FROM `userWHERE `nameLIKE "%后盾%" -- 不走索引 
  8.  
  9. -- 正則表達(dá)式不使用索引,這應(yīng)該很好理解,所以為什么在SQL中很難看到regexp關(guān)鍵字的原因 
  10.  
  11. -- 字符串與數(shù)字比較不使用索引; 
  12. CREATE TABLE `a` (`a` char(10)); 
  13. EXPLAIN SELECT * FROM `a` WHERE `a`="1" -- 走索引 
  14. EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引 
  15.  
  16. select * from dept where dname='xxx' or loc='xx' or deptno=45 --如果條件中有or,即使其中有條件帶索引也不會使用。換言之,就是要求使用的所有字段,都必須建立索引, 我們建議大家盡量避免使用or 關(guān)鍵字 
  17.  
  18. -- 如果mysql估計使用全表掃描要比使用索引快,則不使用索引 

索引雖然好處很多,但過多的使用索引可能帶來相反的問題,索引也是有缺點的:

  • 雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進(jìn)行INSERT,UPDATE和DELETE。因為更新表時,mysql不僅要保存數(shù)據(jù),還要保存一下索引文件
  • 建立索引會占用磁盤空間的索引文件。一般情況這個問題不太嚴(yán)重,但如果你在要給大表上建了多種組合索引,索引文件會膨脹很寬

索引只是提高效率的一個方式,如果mysql有大數(shù)據(jù)量的表,就要花時間研究建立優(yōu)秀的索引,或優(yōu)化查詢語句。

使用索引時,有一些技巧

  1. 索引不會包含有NULL的列

只要列中包含有NULL值,都將不會被包含在索引中,復(fù)合索引中只要有一列含有NULL值,那么這一列對于此符合索引就是無效的。

      2.使用短索引

對串列進(jìn)行索引,如果可以就應(yīng)該指定一個前綴長度。例如,如果有一個char(255)的列,如果在前10個或20個字符內(nèi),多數(shù)值是唯一的,那么就不要對整個列進(jìn)行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。

     3.索引列排序

mysql一張表查詢只能用到一個索引。因此如果where子句中已經(jīng)使用了索引的話,那么order by中的列是不會使用索引的。因此數(shù)據(jù)庫默認(rèn)排序可以符合要求的情況下不要使用排序操作,盡量不要包含多個列的排序,如果需要最好給這些列建復(fù)合索引。這一點是很多程序猿容易忽略的,如where子句的字段建了索引,排序的字段建了索引,但是分開建的,以為會走索引,其實這樣的話排序的字段不會使用索引的,除非建復(fù)合索引,切記。

     4.like語句操作

一般情況下不鼓勵使用like操作,如果非使用不可,注意正確的使用方式。like '%aaa%'不會使用索引,而like 'aaa%'可以使用索引。

    5.不要在列上進(jìn)行運算

    6.不使用NOT IN 、<>、!=操作,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的。

    7.索引要建立在經(jīng)常進(jìn)行select操作的字段上。

這是因為,如果這些列很少用到,那么有無索引并不能明顯改變查詢速度。相反,由于增加了索引,反而降低了系統(tǒng)的維護(hù)速度和增大了空間需求。

    8.索引要建立在值比較唯一的字段上。

    9.對于那些定義為text、image和bit數(shù)據(jù)類型的列不應(yīng)該增加索引。因為這些列的數(shù)據(jù)量要么相當(dāng)大,要么取值很少。

    10.在where和join中出現(xiàn)的列需要建立索引。

     11.where的查詢條件里有不等號(where column != ...),mysql將無法使用索引。

     12.如果where字句的查詢條件里使用了函數(shù)(如:where DAY(column)=...),mysql將無法使用索引。

     13.在join操作中(需要從多個數(shù)據(jù)表提取數(shù)據(jù)時),mysql只有在主鍵和外鍵的數(shù)據(jù)類型相同時才能使用索引,否則即使建立了索引也不會使用。這一點很容易忽略,切記,切記,切記!

     14.在進(jìn)行聯(lián)表查詢時,建立關(guān)聯(lián)的表的字段類型最好一樣且長度一致,這樣能更好的發(fā)揮索引的作用。

      15.組合索引時切記此條約束:組合索引中有多個字段,其中一個字段是有范圍判斷,則需將此字段在最后面。如

  1. ALTER TABLE USER_DEMO ADD INDEX name_age (NAME,AGE); 

因為age會有范圍判斷,則建組合索引時將AGE字段放在后面。

       16.字符集字段比較,UTF8與UTF-BIN聯(lián)合查詢是不能走索引的。

如某張表的order_no字段類型為varchar(50),另一張表的order_no字段類型為varchar(50) COLLATE utf8_BIN。則此時聯(lián)合查詢時不能走索引的,切記。

即兩張表的字段類型如下:

  1. `order_no` varchar(50) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '訂單號'
  2. `order_no` varchar(50) NOT NULL DEFAULT '' COMMENT '訂單號'

       17.以下幾種情況不適合建索引:

  • 表記錄太少
  • 經(jīng)常插入、刪除、修改的表
  • 數(shù)據(jù)重復(fù)且分布平均的表字段。如一個表有10萬行記錄,其中字段column1只有A和B兩種值,且每個值的分布概率大約為50%,那么對這種表column1字段建索引一般不會提高數(shù)據(jù)庫的查詢速度。

       18.給表創(chuàng)建主鍵,對于沒有主鍵的表,在查詢和索引定義上有一定的影響。

       19.避免表字段為null,建議設(shè)置默認(rèn)值(如int類型設(shè)置默認(rèn)值為0),這樣在索引查詢上,效率會高很多。

       20.關(guān)于order by的索引問題重點說下:

  • 無條件查詢?nèi)绻挥衞rder by create_time,即便create_time上有索引,也不會使用到。

           因為優(yōu)化器認(rèn)為走二級索引再去回表成本比全表掃描排序更高,所以選擇走權(quán)標(biāo)掃描。

  • 無條件查詢但是order by create_time limit m,如果m值較小,是可以走索引的。

           因為優(yōu)化器認(rèn)為根據(jù)索引有序性去回表查數(shù)據(jù),然后得到m條數(shù)據(jù),就可以終止循環(huán),

           那么成本比全表掃描小,則選擇走二級索引。

           即便沒有二級索引,mysql針對order by limit也做了優(yōu)化,采用堆排序。

  • order by排序分為file sort和index,index的效率更高。但以下情況不會使用index排序:
  1. 檢查的行數(shù)過多,并且沒有使用覆蓋索引
  2. 使用了多個索引,mysql一次只會采用一個索引
  3. where和order by使用了不同的索引,與上一條類似
  4. order by中加入了非索引列,且非索引列不在where中
  5. 當(dāng)使用left join,使用右邊的表字段排序

 

責(zé)任編輯:華軒 來源: segmentfault
相關(guān)推薦

2023-02-14 08:00:00

MySQL索引查詢

2021-07-19 11:54:15

MySQL優(yōu)先隊列

2021-03-16 08:54:35

AQSAbstractQueJava

2011-07-04 10:39:57

Web

2009-03-16 13:44:29

雙向復(fù)制實例MySQL

2019-11-11 14:51:19

Java數(shù)據(jù)結(jié)構(gòu)Properties

2022-12-02 09:13:28

SeataAT模式

2009-11-30 16:46:29

學(xué)習(xí)Linux

2017-07-02 18:04:53

塊加密算法AES算法

2019-01-07 15:29:07

HadoopYarn架構(gòu)調(diào)度器

2021-07-20 15:20:02

FlatBuffers阿里云Java

2012-05-21 10:06:26

FrameworkCocoa

2022-09-26 09:01:15

語言數(shù)據(jù)JavaScript

2018-03-15 09:13:43

MySQL存儲引擎

2019-11-14 09:53:30

Set集合存儲

2009-12-25 15:49:43

Linux rescu

2023-03-20 09:48:23

ReactJSX

2010-07-26 12:57:12

OPhone游戲開發(fā)

2016-10-14 13:53:05

JavascriptDOMWeb

2016-10-14 14:32:58

JavascriptDOMWeb
點贊
收藏

51CTO技術(shù)棧公眾號