1.索引作用
在索引列上,除了上面提到的有序查找之外,數(shù)據(jù)庫(kù)利用各種各樣的快速定位技術(shù)盆耽,能夠大大提高查詢效率。特別是當(dāng)數(shù)據(jù)量非常大扼菠,查詢涉及多個(gè)表時(shí)摄杂,使用索引往往能使查詢速度加快成千上萬(wàn)倍。
例如循榆,有3個(gè)未索引的表t1析恢、t2、t3冯痢,分別只包含列c1氮昧、c2、c3浦楣,每個(gè)表分別含有1000行數(shù)據(jù)組成,指為1~1000的數(shù)值咪辱,查找對(duì)應(yīng)值相等行的查詢?nèi)缦滤尽?/p>
SELECT c1,c2,c3 FROM t1,t2,t3 WHERE c1=c2 AND c1=c3
此查詢結(jié)果應(yīng)該為1000行振劳,每行包含3個(gè)相等的值。在無(wú)索引的情況下處理此查詢油狂,必須尋找3個(gè)表所有的組合历恐,以便得出與WHERE子句相配的那些行。而可能的組合數(shù)目為1000×1000×1000(十億)专筷,顯然查詢將會(huì)非常慢弱贼。
如果對(duì)每個(gè)表進(jìn)行索引,就能極大地加速查詢進(jìn)程磷蛹。利用索引的查詢處理如下吮旅。
(1)從表t1中選擇第一行,查看此行所包含的數(shù)據(jù)味咳。
(2)使用表t2上的索引庇勃,直接定位t2中與t1的值匹配的行檬嘀。類似,利用表t3上的索引责嚷,直接定位t3中與來(lái)自t1的值匹配的行鸳兽。
(3)掃描表t1的下一行并重復(fù)前面的過(guò)程,直到遍歷t1中所有的行罕拂。
在此情形下揍异,仍然對(duì)表t1執(zhí)行了一個(gè)完全掃描,但能夠在表t2和t3上進(jìn)行索引查找直接取出這些表中的行爆班,比未用索引時(shí)要快一百萬(wàn)倍衷掷。
利用索引,MySQL加速了WHERE子句滿足條件行的搜索蛋济,而在多表連接查詢時(shí)棍鳖,在執(zhí)行連接時(shí)加快了與其他表中的行匹配的速度。
2.創(chuàng)建索引
在執(zhí)行CREATE TABLE語(yǔ)句時(shí)可以創(chuàng)建索引碗旅,也可以單獨(dú)用CREATE INDEX或ALTER TABLE來(lái)為表增加索引渡处。
1.ALTER TABLE
ALTER TABLE用來(lái)創(chuàng)建普通索引、UNIQUE索引或PRIMARY KEY索引祟辟。
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
其中table_name是要增加索引的表名医瘫,column_list指出對(duì)哪些列進(jìn)行索引,多列時(shí)各列之間用逗號(hào)分隔旧困。索引名index_name可選醇份,缺省時(shí),MySQL將根據(jù)第一個(gè)索引列賦一個(gè)名稱吼具。另外僚纷,ALTER TABLE允許在單個(gè)語(yǔ)句中更改多個(gè)表,因此可以在同時(shí)創(chuàng)建多個(gè)索引拗盒。
2.CREATE INDEX
CREATE INDEX可對(duì)表增加普通索引或UNIQUE索引怖竭。
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
table_name、index_name和column_list具有與ALTER TABLE語(yǔ)句中相同的含義陡蝇,索引名不可選痊臭。另外,不能用CREATE INDEX語(yǔ)句創(chuàng)建PRIMARY KEY索引登夫。
3.索引類型
在創(chuàng)建索引時(shí)广匙,可以規(guī)定索引能否包含重復(fù)值。如果不包含恼策,則索引應(yīng)該創(chuàng)建為PRIMARY KEY或UNIQUE索引鸦致。對(duì)于單列惟一性索引,這保證單列不包含重復(fù)的值。對(duì)于多列惟一性索引蹋凝,保證多個(gè)值的組合不重復(fù)鲁纠。
PRIMARY KEY索引和UNIQUE索引非常類似。事實(shí)上鳍寂,PRIMARY KEY索引僅是一個(gè)具有名稱PRIMARY的UNIQUE索引改含。這表示一個(gè)表只能包含一個(gè)PRIMARY KEY,因?yàn)橐粋€(gè)表中不可能具有兩個(gè)同名的索引迄汛。
下面的SQL語(yǔ)句對(duì)students表在sid上添加PRIMARY KEY索引捍壤。
ALTER TABLE students ADD PRIMARY KEY (sid)
4.刪除索引
可利用ALTER TABLE或DROP INDEX語(yǔ)句來(lái)刪除索引。類似于CREATE INDEX語(yǔ)句鞍爱,DROP INDEX可以在ALTER TABLE內(nèi)部作為一條語(yǔ)句處理鹃觉,語(yǔ)法如下。
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY
其中睹逃,前兩條語(yǔ)句是等價(jià)的盗扇,刪除掉table_name中的索引index_name。
第3條語(yǔ)句只在刪除PRIMARY KEY索引時(shí)使用沉填,因?yàn)橐粋€(gè)表只可能有一個(gè)PRIMARY KEY索引疗隶,因此不需要指定索引名。如果沒(méi)有創(chuàng)建PRIMARY KEY索引翼闹,但表具有一個(gè)或多個(gè)UNIQUE索引斑鼻,則MySQL將刪除第一個(gè)UNIQUE索引。
如果從表中刪除了某列猎荠,則索引會(huì)受到影響坚弱。對(duì)于多列組合的索引,如果刪除其中的某列关摇,則該列也會(huì)從索引中刪除荒叶。如果刪除組成索引的所有列,則整個(gè)索引將被刪除输虱。
5.查看索引
mysql> show?index from tblname;
mysql> show keys from tblname;
· Table
表的名稱停撞。
· Non_unique
如果索引不能包括重復(fù)詞,則為0悼瓮。如果可以,則為1艰猬。
· Key_name
索引的名稱横堡。
· Seq_in_index
索引中的列序列號(hào),從1開(kāi)始冠桃。
· Column_name
列名稱命贴。
· Collation
列以什么方式存儲(chǔ)在索引中。在MySQL中,有值‘A’(升序)或NULL(無(wú)分類)胸蛛。
· Cardinality
索引中唯一值的數(shù)目的估計(jì)值污茵。通過(guò)運(yùn)行ANALYZE TABLE或myisamchk -a可以更新≡嵯睿基數(shù)根據(jù)被存儲(chǔ)為整數(shù)的統(tǒng)計(jì)數(shù)據(jù)來(lái)計(jì)數(shù)泞当,所以即使對(duì)于小型表,該值也沒(méi)有必要是精確的民珍〗笫浚基數(shù)越大,當(dāng)進(jìn)行聯(lián)合時(shí)嚷量,MySQL使用該索引的機(jī)會(huì)就越大陋桂。
· Sub_part
如果列只是被部分地編入索引,則為被編入索引的字符的數(shù)目蝶溶。如果整列被編入索引嗜历,則為NULL。
· Packed
指示關(guān)鍵字如何被壓縮抖所。如果沒(méi)有被壓縮梨州,則為NULL。
· Null
如果列含有NULL部蛇,則含有YES摊唇。如果沒(méi)有,則該列含有NO涯鲁。
· Index_type
用過(guò)的索引方法(BTREE, FULLTEXT, HASH, RTREE)巷查。
· Comment
6.什么情況下使用索引表的主關(guān)鍵字
自動(dòng)建立唯一索引
如zl_yhjbqk(用戶基本情況)中的hbs_bh(戶標(biāo)識(shí)編號(hào))
表的字段唯一約束
ORACLE利用索引來(lái)保證數(shù)據(jù)的完整性
如lc_hj(流程環(huán)節(jié))中的lc_bh+hj_sx(流程編號(hào)+環(huán)節(jié)順序)
直接條件查詢的字段
在SQL中用于條件約束的字段
如zl_yhjbqk(用戶基本情況)中的qc_bh(區(qū)冊(cè)編號(hào))
select * from zl_yhjbqk where qc_bh=’7001’
查詢中與其它表關(guān)聯(lián)的字段
字段常常建立了外鍵關(guān)系
如zl_ydcf(用電成份)中的jldb_bh(計(jì)量點(diǎn)表編號(hào))
select * from zl_ydcf a,zl_yhdb b where a.jldb_bh=b.jldb_bh and b.jldb_bh=’540100214511’
查詢中排序的字段
排序的字段如果通過(guò)索引去訪問(wèn)那將大大提高排序速度
select * from zl_yhjbqk order by qc_bh(建立qc_bh索引)
select * from zl_yhjbqk where qc_bh=’7001’ order by cb_sx(建立qc_bh+cb_sx索引,注:只是一個(gè)索引抹腿,其中包括qc_bh和cb_sx字段)
查詢中統(tǒng)計(jì)或分組統(tǒng)計(jì)的字段
select max(hbs_bh) from zl_yhjbqk
select qc_bh,count(*) from zl_yhjbqk group by qc_bh
什么情況下應(yīng)不建或少建索引
表記錄太少
如果一個(gè)表只有5條記錄岛请,采用索引去訪問(wèn)記錄的話,那首先需訪問(wèn)索引表警绩,再通過(guò)索引表訪問(wèn)數(shù)據(jù)表崇败,一般索引表與數(shù)據(jù)表不在同一個(gè)數(shù)據(jù)塊,這種情況下ORACLE至少要往返讀取數(shù)據(jù)塊兩次肩祥。而不用索引的情況下ORACLE會(huì)將所有的數(shù)據(jù)一次讀出后室,處理速度顯然會(huì)比用索引快。
如表zl_sybm(使用部門(mén))一般只有幾條記錄混狠,除了主關(guān)鍵字外對(duì)任何一個(gè)字段建索引都不會(huì)產(chǎn)生性能優(yōu)化岸霹,實(shí)際上如果對(duì)這個(gè)表進(jìn)行了統(tǒng)計(jì)分析后ORACLE也不會(huì)用你建的索引,而是自動(dòng)執(zhí)行全表訪問(wèn)将饺。如:
select * from zl_sybm where sydw_bh=’5401’(對(duì)sydw_bh建立索引不會(huì)產(chǎn)生性能優(yōu)化)
經(jīng)常插入贡避、刪除痛黎、修改的表
對(duì)一些經(jīng)常處理的業(yè)務(wù)表應(yīng)在查詢?cè)试S的情況下盡量減少索引,如zl_yhbm刮吧,gc_dfss湖饱,gc_dfys,gc_fpdy等業(yè)務(wù)表杀捻。
數(shù)據(jù)重復(fù)且分布平均的表字段
假如一個(gè)表有10萬(wàn)行記錄井厌,有一個(gè)字段A只有T和F兩種值,且每個(gè)值的分布概率大約為50%水醋,那么對(duì)這種表A字段建索引一般不會(huì)提高數(shù)據(jù)庫(kù)的查詢速度旗笔。
經(jīng)常和主字段一塊查詢但主字段索引值比較多的表字段
如gc_dfss(電費(fèi)實(shí)收)表經(jīng)常按收費(fèi)序號(hào)、戶標(biāo)識(shí)編號(hào)拄踪、抄表日期蝇恶、電費(fèi)發(fā)生年月、操作 標(biāo)志來(lái)具體查詢某一筆收款的情況惶桐,如果將所有的字段都建在一個(gè)索引里那將會(huì)增加數(shù)據(jù)的修改撮弧、插入、刪除時(shí)間姚糊,從實(shí)際上分析一筆收款如果按收費(fèi)序號(hào)索引就已 經(jīng)將記錄減少到只有幾條贿衍,如果再按后面的幾個(gè)字段索引查詢將對(duì)性能不產(chǎn)生太大的影響。
對(duì)千萬(wàn)級(jí)MySQL數(shù)據(jù)庫(kù)建立索引的事項(xiàng)及提高性能的手段
一救恨、注意事項(xiàng):
首先贸辈,應(yīng)當(dāng)考慮表空間和磁盤(pán)空間是否足夠。我們知道索引也是一種數(shù)據(jù)肠槽,在建立索引的時(shí)候勢(shì)必也會(huì)占用大量表空間擎淤。因此在對(duì)一大表建立索引的時(shí)候首先應(yīng)當(dāng)考慮的是空間容量問(wèn)題。
其次秸仙,在對(duì)建立索引的時(shí)候要對(duì)表進(jìn)行加鎖嘴拢,因此應(yīng)當(dāng)注意操作在業(yè)務(wù)空閑的時(shí)候進(jìn)行。
二寂纪、性能調(diào)整方面:
首當(dāng)其沖的考慮因素便是磁盤(pán)I/O席吴。物理上,應(yīng)當(dāng)盡量把索引與數(shù)據(jù)分散到不同的磁盤(pán)上(不考慮陣列的情況)捞蛋。邏輯上孝冒,數(shù)據(jù)表空間與索引表空間分開(kāi)。這是在建索引時(shí)應(yīng)當(dāng)遵守的基本準(zhǔn)則拟杉。
其次迈倍,我們知道,在建立索引的時(shí)候要對(duì)表進(jìn)行全表的掃描工作捣域,因此啼染,應(yīng)當(dāng)考慮調(diào)大初始化參數(shù)db_file_multiblock_read_count的值。一般設(shè)置為32或更大焕梅。
再次迹鹅,建立索引除了要進(jìn)行全表掃描外同時(shí)還要對(duì)數(shù)據(jù)進(jìn)行大量的排序操作,因此贞言,應(yīng)當(dāng)調(diào)整排序區(qū)的大小斜棚。
9i之前,可以在session級(jí)別上加大sort_area_size的大小该窗,比如設(shè)置為100m或者更大弟蚀。
9i以后,如果初始化參數(shù)workarea_size_policy的值為T(mén)RUE酗失,則排序區(qū)從pga_aggregate_target里自動(dòng)分配獲得义钉。
最后,建立索引的時(shí)候规肴,可以加上nologging選項(xiàng)捶闸。以減少在建立索引過(guò)程中產(chǎn)生的大量redo,從而提高執(zhí)行的速度拖刃。
MySql在建立索引優(yōu)化時(shí)需要注意的問(wèn)題
設(shè)計(jì)好MySql的索引可以讓你的數(shù)據(jù)庫(kù)飛起來(lái)删壮,大大的提高數(shù)據(jù)庫(kù)效率。設(shè)計(jì)MySql索引的時(shí)候有一下幾點(diǎn)注意:
1兑牡,創(chuàng)建索引
對(duì)于查詢占主要的應(yīng)用來(lái)說(shuō)央碟,索引顯得尤為重要。很多時(shí)候性能問(wèn)題很簡(jiǎn)單的就是因?yàn)槲覀兺颂砑铀饕斐傻木蛘哒f(shuō)沒(méi)有添加更為有效的索引導(dǎo)致亿虽。如果不加
索引的話,那么查找任何哪怕只是一條特定的數(shù)據(jù)都會(huì)進(jìn)行一次全表掃描边酒,如果一張表的數(shù)據(jù)量很大而符合條件的結(jié)果又很少经柴,那么不加索引會(huì)引起致命的性能下
降。但是也不是什么情況都非得建索引不可墩朦,比如性別可能就只有兩個(gè)值坯认,建索引不僅沒(méi)什么優(yōu)勢(shì),還會(huì)影響到更新速度氓涣,這被稱為過(guò)度索引牛哺。
2,復(fù)合索引
比如有一條語(yǔ)句是這樣的:select * from users where area=’beijing’ and age=22;
如果我們是在area和age上分別創(chuàng)建單個(gè)索引的話劳吠,由于mysql查詢每次只能使用一個(gè)索引引润,所以雖然這樣已經(jīng)相對(duì)不做索引時(shí)全表掃描提高了很多效
率,但是如果在area痒玩、age兩列上創(chuàng)建復(fù)合索引的話將帶來(lái)更高的效率淳附。如果我們創(chuàng)建了(area, age,
salary)的復(fù)合索引议慰,那么其實(shí)相當(dāng)于創(chuàng)建了(area,age,salary)、(area,age)奴曙、(area)三個(gè)索引别凹,這被稱為最佳左前綴
特性。因此我們?cè)趧?chuàng)建復(fù)合索引時(shí)應(yīng)該將最常用作限制條件的列放在最左邊洽糟,依次遞減炉菲。
3,索引不會(huì)包含有NULL值的列
只要列中包含有NULL值都將不會(huì)被包含在索引中坤溃,復(fù)合索引中只要有一列含有NULL值拍霜,那么這一列對(duì)于此復(fù)合索引就是無(wú)效的。所以我們?cè)跀?shù)據(jù)庫(kù)設(shè)計(jì)時(shí)不要讓字段的默認(rèn)值為NULL薪介。
4祠饺,使用短索引
對(duì)串列進(jìn)行索引,如果可能應(yīng)該指定一個(gè)前綴長(zhǎng)度昭灵。例如吠裆,如果有一個(gè)CHAR(255)的 列,如果在前10 個(gè)或20 個(gè)字符內(nèi)烂完,多數(shù)值是惟一的试疙,那么就不要對(duì)整個(gè)列進(jìn)行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤(pán)空間和I/O操作抠蚣。
5祝旷,排序的索引問(wèn)題
mysql查詢只使用一個(gè)索引,因此如果where子句中已經(jīng)使用了索引的話嘶窄,那么order by中的列是不會(huì)使用索引的怀跛。因此數(shù)據(jù)庫(kù)默認(rèn)排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個(gè)列的排序柄冲,如果需要最好給這些列創(chuàng)建復(fù)合索引吻谋。
6,like語(yǔ)句操作
一般情況下不鼓勵(lì)使用like操作现横,如果非使用不可漓拾,如何使用也是一個(gè)問(wèn)題。like “%aaa%” 不會(huì)使用索引而like “aaa%”可以使用索引戒祠。
7骇两,不要在列上進(jìn)行運(yùn)算
select * from users where
YEAR(adddate)
8,不使用NOT IN和操作
NOT IN和操作都不會(huì)使用索引將進(jìn)行全表掃描姜盈。NOT IN可以NOT EXISTS代替低千,id3則可使用id>3 or id