數(shù)據(jù)庫(kù)的優(yōu)化,最大的一點(diǎn):索引的建立,那么你寫過(guò)這么多的sql語(yǔ)句,真的會(huì)用索引么,或者說(shuō)會(huì)用索引么?體驗(yàn)過(guò)百萬(wàn)級(jí)別的查詢速度么?
為什么要使用索引妖啥?
索引能夠加速表中數(shù)據(jù)的查找和排序晚岭,索引是一個(gè)單獨(dú)建立 的物理數(shù)據(jù)庫(kù),并且包含
一個(gè)指向數(shù)據(jù)表中指定列的數(shù)據(jù)值指針(指向?qū)?yīng)數(shù)據(jù)的指針)囊榜。
作用:
1. 快速查詢數(shù)據(jù)
2.保證數(shù)據(jù)的唯一性
3. 實(shí)現(xiàn)表與表之間的參照完整性
4.在使用order by、group by子句進(jìn)行數(shù)據(jù)檢索時(shí)肛循,利用索引 可以減少排序和分組的時(shí)間甥桂。
優(yōu)點(diǎn):
1. 大大加快數(shù)據(jù)檢索速度
2. 創(chuàng)建唯一索引,保證數(shù)據(jù)庫(kù)表中每行數(shù)據(jù)的唯一性
3. 加速表之間的連接
4. 減少查詢中分組和排序的時(shí)間
缺點(diǎn):
1.需要占用物理空間
2. 對(duì)表中數(shù)據(jù)進(jìn)行增加券时、刪除和修改時(shí)索引也要更新孤里,降低了數(shù)據(jù)維護(hù)速度
一.索引的分類(聚集索引,非聚合索引,復(fù)合索引)
1.聚集(clustered)索引,也叫聚簇索引橘洞。
定義:表中行的物理順序與鍵值的邏輯(索引)順序相同捌袜。因?yàn)閿?shù)據(jù)的物理順序只能有一種,所以一張表只能有一個(gè)聚集索引震檩。如果一張表沒(méi)有聚集索引琢蛤,那么這張表就沒(méi)有順序的概念,所有的新行都會(huì)插入到表的末尾。對(duì)于聚集索引抛虏,葉節(jié)點(diǎn)即存儲(chǔ)了數(shù)據(jù)行博其,不再有單獨(dú)的數(shù)據(jù)頁(yè)。
定義比較抽象,舉個(gè)實(shí)際的例子:
一個(gè)表就像是我們以前用的新華字典迂猴,聚集索引就像是拼音目錄慕淡,而每個(gè)字存放的頁(yè)碼就是我們的數(shù)據(jù)物理地址,我們?nèi)绻樵円粋€(gè)“哇”字沸毁,我們只需要查詢“哇”字對(duì)應(yīng)在新華字典拼音目錄對(duì)應(yīng)的頁(yè)碼峰髓,就可以查詢到對(duì)應(yīng)的“哇”字所在的位置傻寂,而拼音目錄對(duì)應(yīng)的A-Z的字順序,和新華字典實(shí)際存儲(chǔ)的字的順序A-Z也是一樣的携兵,如果我們中文新出了一個(gè)字疾掰,拼音開(kāi)頭第一個(gè)是B,那么他插入的時(shí)候也要按照拼音目錄順序插入到A字的后面
下面看個(gè)數(shù)據(jù),解釋下數(shù)據(jù)物理地址:
地址 id username age
0x01 1 小張 11
0x02 2 小紅 12
0x03 3 小華 11
.. .. .. ..
0xff 256 小英 12
第一列的地址表示該行數(shù)據(jù)在磁盤中的物理地址徐紧,后面三列才 是我們SQL里面用的表里的列,
其中id是主鍵静檬,建立了聚集索引.結(jié)合上面的表格就可以理解這句話了吧:數(shù)據(jù)行的物理順序與列值的順序相同,
如果我們查詢id比較靠后的數(shù)據(jù)并级,那么這行數(shù)據(jù)的地址在磁盤中的物理地址也會(huì)比較后,而且由于物理排列方式與聚集索引的順序相同,所以也就只能建立一個(gè)聚集索引了.
不理解?咱們?cè)儆脠D來(lái)說(shuō)明
樹(shù)節(jié)點(diǎn)1下面有2和2的節(jié)點(diǎn),也可以看作數(shù)據(jù)節(jié)點(diǎn),是不是可以直接獲取到對(duì)應(yīng)的全部列的數(shù)據(jù)?這個(gè)就是聚集索引所有的優(yōu)勢(shì)
2.創(chuàng)建聚集索引(注:Sqlite不支持聚集索引)
2.1. 如果不創(chuàng)建索引拂檩,系統(tǒng)會(huì)自動(dòng)創(chuàng)建一個(gè)隱含列作為表的聚集索引。
create table t1(
id int primary key,
name nvarchar(255)
)
2.2.創(chuàng)建表后添加聚集索引
SQL Server
create clustered index clustered_index on table_name(colum_name)
MySQL
alter table table_name add primary key(colum_name)
值得注意的是嘲碧,最好還是在創(chuàng)建表的時(shí)候添加聚集索引稻励,由于聚集索引的物理順序上的特殊性,
因此如果再在上面創(chuàng)建索引的時(shí)候會(huì)根據(jù)索引列的排序移動(dòng)全部數(shù)據(jù)行上面的順序愈涩,會(huì)非常地耗費(fèi)時(shí)間以及性能望抽。
二.非聚集索引
定義:該索引中索引的邏輯順序與磁盤上行的物理存儲(chǔ)順序不同,一個(gè)表中可以擁有多個(gè)非
聚集索引钠署。
可以這樣理解:除了聚集索引以外的索引都是非聚集索引糠聪,只是人們想細(xì)分一下非聚集索引,
分成普通索引谐鼎,唯一索引舰蟆,全文索引。如果非要把非聚集索引類比成現(xiàn)實(shí)生活中的東西狸棍,那
么非聚集索引就像新華字典的偏旁字典身害,他結(jié)構(gòu)順序與實(shí)際存放順序不一定一致。
通俗點(diǎn)的理解就是:索引節(jié)點(diǎn)跟聚集節(jié)點(diǎn)是一樣的,只是查詢的時(shí)候,定義的索引在其他列上并沒(méi)有覆蓋,這時(shí)候還得去這個(gè)沒(méi)有覆蓋的列上再查詢,這就需要二次查詢了
標(biāo)準(zhǔn)的說(shuō)法是:非聚集索引葉節(jié)點(diǎn)仍然是索引節(jié)點(diǎn)草戈,只是有一個(gè)指針指向?qū)?yīng)的數(shù)據(jù)塊塌鸯,此如
果使用非聚集索引查詢,而查詢列中包含了其他該索引沒(méi)有覆蓋的列唐片,那么他還要進(jìn)行第二
次的查詢丙猬,查詢節(jié)點(diǎn)上對(duì)應(yīng)的數(shù)據(jù)行的數(shù)據(jù)。
舉個(gè)例子:
id username age
1 小張 11
2 小紅 12
3 小華 11
.. .. ..
256 小英 12
以及聚集索引clustered index(id), 非聚集索引index(username)费韭。
使用以下語(yǔ)句進(jìn)行查詢茧球,不需要進(jìn)行二次查詢,直接就可以從非聚集索引的節(jié)點(diǎn)里面就可以獲取
到查詢列的數(shù)據(jù)星持。
select id, username from t1 where username = '小張'
select username from t1 where username = '小張'
但是使用以下語(yǔ)句進(jìn)行查詢抢埋,就需要二次的查詢?nèi)カ@取原數(shù)據(jù)行的score:
select username, age from t1 where username = '小張'
如何解決非聚集索引的二次查詢問(wèn)題?使用復(fù)合索引
三:復(fù)合索引(索引生效講解)
復(fù)合索引(覆蓋索引)顧名思義就是建立兩列以上的索引,即可查詢復(fù)合索引里的列的數(shù)據(jù)而不需要進(jìn)行回表二次查詢,如index(col1, col2)揪垄,執(zhí)行下面的語(yǔ)句:
select col1, col2 from t1 where col1 = 'xxx';
注意:在查詢使用時(shí)穷吮,最好將條件順序按找索引的順序,這樣效率最高
舉些例子:
CREATE INDEX index_table ON table(x, y, z)創(chuàng)建索引
那么x,xy,xyz都是前導(dǎo)列饥努,而yz捡鱼,y,z這樣的就不是
索引生效的條件:
前序列必須使用等于或者in操作最右邊的列可以使用不等式肪凛,這樣索引才可以完全生效堰汉。
同時(shí)辽社,where子句中的列不需要全建立了索引伟墙,但是必須保證建立索引的列之間沒(méi)有間隙
CREATE INDEX idx_ex1 ON ex1(a,b,c,d,e,...,y,z);
WHERE a=5 AND b IN (1,2,3) AND c IS NULL AND d='hello'
這顯然對(duì)于abcd四列都是有效的,因?yàn)橹挥械扔诤蚷n操作滴铅,并且是前導(dǎo)列戳葵。
再看三個(gè)查詢語(yǔ)句:
WHERE a=5 AND b IN (1,2,3) AND c>12 AND d='hello'
那這里只有a,b和c的索引會(huì)是有效的汉匙,d列的索引會(huì)失效拱烁,因?yàn)樗赾列的右邊,而c列使用
了不等式噩翠,根據(jù)使用不等式的限制戏自,c列已經(jīng)屬于最右邊。
WHERE b=5 AND c=3 AND d = 'hello'
不生效,沒(méi)有按照索引順序
WHERE d = 'hello'
不生效,沒(méi)有按照索引順序
最后再看一條:
WHERE b IN (1,2,3) AND c NOT NULL AND d='hello'
索引將不會(huì)被生效伤锚,因?yàn)闆](méi)有使用前導(dǎo)列,a不在擅笔,這個(gè)查詢會(huì)是一個(gè)全表查詢。
對(duì)于between屯援,or猛们,like,都無(wú)法使用索引狞洋。必須要用對(duì)應(yīng)的等式來(lái)生效索引
between:
WHERE scope BETWEEN 100 and 202;
這時(shí)就應(yīng)該將其轉(zhuǎn)換成:
WHERE scope >= 10 AND scope <= 20;
like:
index_table WHERE scope LIKE 'sql%';;
此時(shí)應(yīng)該將它轉(zhuǎn)換成:
WHERE scope >= 'sql' AND scope < 'xxx';
or(用in):
WHERE scope = 'abc' OR scope = 'xyz';
此時(shí)應(yīng)該將它轉(zhuǎn)換成:
WHERE scope IN ('abc', 'xyz');
總結(jié):
1.使用聚集索引的查詢效率要比非聚集索引的效率要高弯淘,但是如果需要頻繁去改變聚集索引的值,寫入性能并不高吉懊,因?yàn)樾枰苿?dòng)對(duì)應(yīng)數(shù)據(jù)的物理位置庐橙。
2.非聚集索引在查詢的時(shí)候可以的話就避免二次查詢,這樣性能會(huì)大幅提升借嗽。
3.索引有助于提高檢索性能态鳖,但過(guò)多或不當(dāng)?shù)乃饕矔?huì)導(dǎo)致系統(tǒng)低效。因?yàn)橛脩粼诒碇忻考舆M(jìn)一個(gè)索引淹魄,數(shù)據(jù)庫(kù)就要做更多的工作郁惜。過(guò)多的索引甚至?xí)?dǎo)致索引碎片
聯(lián)想問(wèn)題?:
復(fù)合索引會(huì)替代單一索引么?