mysql 左连接 怎么走索引_数据库索引、左连接、右连接、等值连接
在MySQL中,主要有四種類(lèi)型的索引,分別為:B-Tree索引,Hash索引,Fulltext索引(MyISAM 表)和R-Tree索引,本文講的是B-Tree索引。
一、Mysql索引主要有兩種結(jié)構(gòu):B+Tree索引和Hash索引
(a) Innodb存儲(chǔ)引擎 默認(rèn)是 B+Tree索引
(b) MyISAM 存儲(chǔ)引擎 默認(rèn)是Fulltext索引;
(c)Memory 存儲(chǔ)引擎 默認(rèn) Hash索引;
Hash索引
mysql中,只有Memory(Memory表只存在內(nèi)存中,斷電會(huì)消失,適用于臨時(shí)表)存儲(chǔ)引擎顯示支持Hash索引,是Memory表的默認(rèn)索引類(lèi)型,盡管Memory表也可以使用B+Tree索引。Hash索引把數(shù)據(jù)以hash形式組織起來(lái),因此當(dāng)查找某一條記錄的時(shí)候,速度非常快。但是因?yàn)閔ash結(jié)構(gòu),每個(gè)鍵只對(duì)應(yīng)一個(gè)值,而且是散列的方式分布。所以它并不支持范圍查找和排序等功能。
B+Tree索引
B+Tree是mysql使用最頻繁的一個(gè)索引數(shù)據(jù)結(jié)構(gòu),是Innodb和Myisam存儲(chǔ)引擎模式的索引類(lèi)型。相對(duì)Hash索引,B+Tree在查找單條記錄的速度比不上Hash索引,但是因?yàn)楦m合排序等操作,所以它更受歡迎。畢竟不可能只對(duì)數(shù)據(jù)庫(kù)進(jìn)行單條記錄的操作。
帶順序訪問(wèn)指針的B+Tree
B+Tree所有索引數(shù)據(jù)都在葉子節(jié)點(diǎn)上,并且增加了順序訪問(wèn)指針,每個(gè)葉子節(jié)點(diǎn)都有指向相鄰葉子節(jié)點(diǎn)的指針。
這樣做是為了提高區(qū)間效率,例如查詢(xún)key為從18到49的所有數(shù)據(jù)記錄,當(dāng)找到18后,只要順著節(jié)點(diǎn)和指針順序遍歷就可以以此向訪問(wèn)到所有數(shù)據(jù)節(jié)點(diǎn),極大提高了區(qū)間查詢(xún)效率。
大大減少磁盤(pán)I/O讀取
數(shù)據(jù)庫(kù)系統(tǒng)的設(shè)計(jì)者巧妙利用了磁盤(pán)預(yù)讀原理,將一個(gè)節(jié)點(diǎn)的大小設(shè)為等于一個(gè)頁(yè),這樣每個(gè)節(jié)點(diǎn)需要一次I/O就可以完全載入。
什么是索引
索引(Index)是幫助數(shù)據(jù)庫(kù)高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。索引是在基于數(shù)據(jù)庫(kù)表創(chuàng)建的,它包含一個(gè)表中某些列的值以及記錄對(duì)應(yīng)的地址,并且把這些值存儲(chǔ)在一個(gè)數(shù)據(jù)結(jié)構(gòu)中。最常見(jiàn)的就是使用哈希表、B+樹(shù)作為索引。
一般的應(yīng)用系統(tǒng),讀寫(xiě)比例在10:1左右,而且插入操作和一般的更新操作很少出現(xiàn)性能問(wèn)題,在生產(chǎn)環(huán)境中,我們遇到最多的,也是最容易出問(wèn)題的,還是一些復(fù)雜的查詢(xún)操作,因此對(duì)查詢(xún)語(yǔ)句的優(yōu)化顯然是重中之重。說(shuō)起加速查詢(xún),就不得不提到索引了。
為什么要使用索引
我們知道,數(shù)據(jù)庫(kù)查詢(xún)是數(shù)據(jù)庫(kù)最主要的功能之一。而查詢(xún)速度當(dāng)然是越快越好。而當(dāng)數(shù)據(jù)量越來(lái)越大的時(shí)候,查詢(xún)花費(fèi)的時(shí)間會(huì)隨之增長(zhǎng)。而索引,可以加速數(shù)據(jù)的查詢(xún)。因?yàn)樗饕怯行蚺帕械摹?/p>
舉個(gè)例子來(lái)說(shuō),假設(shè)我們有一個(gè)數(shù)據(jù)庫(kù)表Employee,這個(gè)表分別有三個(gè)字段:name,age,address。假設(shè)表中有1000條記錄。
假如沒(méi)有使用索引,當(dāng)我們查詢(xún)名為“Jesus”的雇員的時(shí)候,即調(diào)用:
select name,age,address from Employee where name = 'Jesus';
此時(shí)數(shù)據(jù)庫(kù)不得不在Employee表中對(duì)這1000條記錄一條一條的進(jìn)行判斷name字段是否為“Jesus”。這也就是所謂的全表掃描。
而當(dāng)我們?cè)贓mployee表上的name字段上創(chuàng)建索引時(shí),當(dāng)我們查詢(xún)名為“Jesus”的雇員時(shí),會(huì)通過(guò)索引查找去查詢(xún)名為“Jesus”的雇員,因?yàn)樵撍饕呀?jīng)按照字母順序排列,因此要查找名為“Jesus”的記錄時(shí)會(huì)快很多,因?yàn)槊质鬃帜笧椤癑”的雇員都是排列在一起的。通過(guò)該索引,能獲取到表中對(duì)應(yīng)的記錄。
二叉查找樹(shù)
二叉查找樹(shù)也稱(chēng)為有序二叉查找樹(shù),滿(mǎn)足二叉查找樹(shù)的一般性質(zhì),是指一棵空樹(shù)具有如下性質(zhì):
1、任意節(jié)點(diǎn)左子樹(shù)不為空,則左子樹(shù)的值均小于根節(jié)點(diǎn)的值;
2、任意節(jié)點(diǎn)右子樹(shù)不為空,則右子樹(shù)的值均大于于根節(jié)點(diǎn)的值;
3、任意節(jié)點(diǎn)的左右子樹(shù)也分別是二叉查找樹(shù);
4、沒(méi)有鍵值相等的節(jié)點(diǎn);
平衡二叉樹(shù)
樹(shù)形結(jié)構(gòu)是計(jì)算機(jī)系統(tǒng)里最重要的數(shù)據(jù)結(jié)構(gòu)。
我們知道,二叉樹(shù)的查找的時(shí)間復(fù)雜度是O(log2N),其查找效率與深度有關(guān),而普通的二叉樹(shù)可能由于內(nèi)部節(jié)點(diǎn)排列問(wèn)題退化成鏈表,這樣查找效率就會(huì)很低。因此平衡二叉樹(shù)是更好的選擇,因?yàn)樗3制胶?#xff0c;即通過(guò)旋轉(zhuǎn)調(diào)整結(jié)構(gòu)保持最小的深度。其查找的時(shí)間復(fù)雜度也是O(log2N)。
但實(shí)際上,數(shù)據(jù)庫(kù)中索引的結(jié)構(gòu)也并非AVL樹(shù)或更優(yōu)秀的紅黑樹(shù),盡管它的查詢(xún)的時(shí)間復(fù)雜度很低。
為什么平衡二叉樹(shù)也不適合作為索引
之前說(shuō)了平衡樹(shù)的查找時(shí)間復(fù)雜度是O(log2N),已經(jīng)很不錯(cuò)了,但還是不適合作為索引結(jié)構(gòu)。那么肯定是有一種更適合作為索引的數(shù)據(jù)結(jié)構(gòu)。那么這個(gè)更適合作為索引的數(shù)據(jù)結(jié)構(gòu),難道是查找的時(shí)間復(fù)雜度更低嗎?并不是。這種作為索引的數(shù)據(jù)結(jié)構(gòu)的查找的時(shí)間復(fù)雜度也近似O(log2N)。
那為什么平衡二叉樹(shù)不適合作為索引呢?
索引是存在于索引文件中,是存在于磁盤(pán)中的。因?yàn)樗饕ǔJ呛艽蟮?#xff0c;因此無(wú)法一次將全部索引加載到內(nèi)存當(dāng)中,因此每次只能從磁盤(pán)中讀取一個(gè)磁盤(pán)頁(yè)的數(shù)據(jù)到內(nèi)存中。而這個(gè)磁盤(pán)的讀取的速度較內(nèi)存中的讀取速度而言是差了好幾個(gè)級(jí)別。
注意,我們說(shuō)的平衡二叉樹(shù)結(jié)構(gòu),指的是邏輯結(jié)構(gòu)上的平衡二叉樹(shù),其物理實(shí)現(xiàn)是數(shù)組。然后由于在邏輯結(jié)構(gòu)上相近的節(jié)點(diǎn)在物理結(jié)構(gòu)上可能會(huì)差很遠(yuǎn)。因此,每次讀取的磁盤(pán)頁(yè)的數(shù)據(jù)中有許多是用不上的。因此,查找過(guò)程中要進(jìn)行許多次的磁盤(pán)讀取操作。
而適合作為索引的結(jié)構(gòu)應(yīng)該是盡可能少的執(zhí)行磁盤(pán)IO操作,因?yàn)閳?zhí)行磁盤(pán)IO操作非常的耗時(shí)。因此,平衡二叉樹(shù)并不適合作為索引結(jié)構(gòu)。
B樹(shù)的性質(zhì)
1、定義任意非葉子結(jié)點(diǎn)最多只有M個(gè)兒子,且M>2;
2、根結(jié)點(diǎn)的兒子數(shù)為[2, M];
3、除根結(jié)點(diǎn)以外的非葉子結(jié)點(diǎn)的兒子數(shù)為[M/2, M];
4、每個(gè)結(jié)點(diǎn)存放至少M(fèi)/2-1(取上整)和至多M-1個(gè)關(guān)鍵字;(至少2個(gè)關(guān)鍵字)
5、非葉子結(jié)點(diǎn)的關(guān)鍵字個(gè)數(shù)=指向兒子的指針個(gè)數(shù)-1;
6、非葉子結(jié)點(diǎn)的關(guān)鍵字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7、非葉子結(jié)點(diǎn)的指針:P[1], P[2], …, P[M];其中P[1]指向關(guān)鍵字小于K[1]的子樹(shù),P[M]指向關(guān)鍵字大于K[M-1]的子樹(shù),其它P[i]指向關(guān)鍵字屬于(K[i-1], K[i])的子樹(shù);
8、所有葉子結(jié)點(diǎn)位于同一層;
B+樹(shù)
比B樹(shù)更適合作為索引的結(jié)構(gòu)是B+樹(shù)。MySQL中也是使用B+樹(shù)作為索引。它是B樹(shù)的變種,因此是基于B樹(shù)來(lái)改進(jìn)的。為什么B+樹(shù)會(huì)比B樹(shù)更加優(yōu)秀呢?
B樹(shù):有序數(shù)組+平衡多叉樹(shù);
B+樹(shù):有序數(shù)組鏈表+平衡多叉樹(shù);
B+樹(shù)的關(guān)鍵字全部存放在葉子節(jié)點(diǎn)中,非葉子節(jié)點(diǎn)用來(lái)做索引,而葉子節(jié)點(diǎn)中有一個(gè)指針指向一下個(gè)葉子節(jié)點(diǎn)。做這個(gè)優(yōu)化的目的是為了提高區(qū)間訪問(wèn)的性能。而正是這個(gè)特性決定了B+樹(shù)更適合用來(lái)存儲(chǔ)外部數(shù)據(jù)。
MYSQL為什么采用B樹(shù)而不是B+樹(shù)
1、?B+樹(shù)的磁盤(pán)讀寫(xiě)代價(jià)更低:B+樹(shù)的內(nèi)部節(jié)點(diǎn)并沒(méi)有指向關(guān)鍵字具體信息的指針,因此其內(nèi)部節(jié)點(diǎn)相對(duì)B樹(shù)更小,如果把所有同一內(nèi)部節(jié)點(diǎn)的關(guān)鍵字存放在同一盤(pán)塊中,那么盤(pán)塊所能容納的關(guān)鍵字?jǐn)?shù)量也越多,一次性讀入內(nèi)存的需要查找的關(guān)鍵字也就越多,相對(duì)IO讀寫(xiě)次數(shù)就降低了。
2、B+樹(shù)的查詢(xún)效率更加穩(wěn)定:由于非終結(jié)點(diǎn)并不是最終指向文件內(nèi)容的結(jié)點(diǎn),而只是葉子結(jié)點(diǎn)中關(guān)鍵字的索引。所以任何關(guān)鍵字的查找必須走一條從根結(jié)點(diǎn)到葉子結(jié)點(diǎn)的路。所有關(guān)鍵字查詢(xún)的路徑長(zhǎng)度相同,導(dǎo)致每一個(gè)數(shù)據(jù)的查詢(xún)效率相當(dāng)。
3、由于B+樹(shù)的數(shù)據(jù)都存儲(chǔ)在葉子結(jié)點(diǎn)中,分支結(jié)點(diǎn)均為索引,方便掃庫(kù),只需要掃一遍葉子結(jié)點(diǎn)即可,但是B樹(shù)因?yàn)槠浞种ЫY(jié)點(diǎn)同樣存儲(chǔ)著數(shù)據(jù),我們要找到具體的數(shù)據(jù),需要進(jìn)行一次中序遍歷按序來(lái)掃,所以B+樹(shù)更加適合在區(qū)間查詢(xún)的情況,所以通常B+樹(shù)用于數(shù)據(jù)庫(kù)索引。
數(shù)據(jù)庫(kù)索引采用B+樹(shù)的主要原因是B樹(shù)在提高了磁盤(pán)IO性能的同時(shí)并沒(méi)有解決元素遍歷的效率低下的問(wèn)題。正是為了解決這個(gè)問(wèn)題,B+樹(shù)應(yīng)運(yùn)而生。
B+樹(shù)只要遍歷葉子節(jié)點(diǎn)就可以實(shí)現(xiàn)整棵樹(shù)的遍歷。而且在數(shù)據(jù)庫(kù)中基于范圍的查詢(xún)是非常頻繁的,而B(niǎo)樹(shù)不支持這樣的操作(或者說(shuō)效率太低)。
正如上面所說(shuō),在數(shù)據(jù)庫(kù)中基于范圍的查詢(xún)是非常頻繁的,因此MySQL最終選擇的索引結(jié)構(gòu)是B+樹(shù)而不是B樹(shù)。
b+樹(shù)性質(zhì)
1.索引字段要盡量的小:通過(guò)上面的分析,我們知道IO次數(shù)取決于b+數(shù)的高度h,假設(shè)當(dāng)前數(shù)據(jù)表的數(shù)據(jù)為N,每個(gè)磁盤(pán)塊的數(shù)據(jù)項(xiàng)的數(shù)量是m,則有h=㏒(m+1)N,當(dāng)數(shù)據(jù)量N一定的情況下,m越大,h越小;而m = 磁盤(pán)塊的大小 / 數(shù)據(jù)項(xiàng)的大小,磁盤(pán)塊的大小也就是一個(gè)數(shù)據(jù)頁(yè)的大小,是固定的,如果數(shù)據(jù)項(xiàng)占的空間越小,數(shù)據(jù)項(xiàng)的數(shù)量越多,樹(shù)的高度越低。這就是為什么每個(gè)數(shù)據(jù)項(xiàng),即索引字段要盡量的小,比如int占4字節(jié),要比bigint8字節(jié)少一半。這也是為什么b+樹(shù)要求把真實(shí)的數(shù)據(jù)放到葉子節(jié)點(diǎn)而不是內(nèi)層節(jié)點(diǎn),一旦放到內(nèi)層節(jié)點(diǎn),磁盤(pán)塊的數(shù)據(jù)項(xiàng)會(huì)大幅度下降,導(dǎo)致樹(shù)增高。當(dāng)數(shù)據(jù)項(xiàng)等于1時(shí)將會(huì)退化成線性表。
2.索引的最左匹配特性(即從左往右匹配):當(dāng)b+樹(shù)的數(shù)據(jù)項(xiàng)是復(fù)合的數(shù)據(jù)結(jié)構(gòu),比如(name,age,sex)的時(shí)候,b+數(shù)是按照從左到右的順序來(lái)建立搜索樹(shù)的,比如當(dāng)(張三,20,F)這樣的數(shù)據(jù)來(lái)檢索的時(shí)候,b+樹(shù)會(huì)優(yōu)先比較name來(lái)確定下一步的所搜方向,如果name相同再依次比較age和sex,最后得到檢索的數(shù)據(jù);但當(dāng)(20,F)這樣的沒(méi)有name的數(shù)據(jù)來(lái)的時(shí)候,b+樹(shù)就不知道下一步該查哪個(gè)節(jié)點(diǎn),因?yàn)榻⑺阉鳂?shù)的時(shí)候name就是第一個(gè)比較因子,必須要先根據(jù)name來(lái)搜索才能知道下一步去哪里查詢(xún)。比如當(dāng)(張三,F)這樣的數(shù)據(jù)來(lái)檢索時(shí),b+樹(shù)可以用name來(lái)指定搜索方向,但下一個(gè)字段age的缺失,所以只能把名字等于張三的數(shù)據(jù)都找到,然后再匹配性別是F的數(shù)據(jù)了, 這個(gè)是非常重要的性質(zhì),即索引的最左匹配特性。
這也是經(jīng)常考察的,比如 我定義了 A,B,C的聯(lián)合索引,如果 我只傳遞了 A,B 能走索引嗎?答案是能,因?yàn)樽钭髠?cè)原理
索引使用注意事項(xiàng)
1,不要濫用索引
①,索引提高查詢(xún)速度,卻會(huì)降低更新表的速度,因?yàn)楦卤頃r(shí),mysql不僅要更新數(shù)據(jù),保存數(shù)據(jù),還要更新索引,保存索引
②,索引會(huì)占用磁盤(pán)空間
2,索引不會(huì)包含含有NULL值的列
復(fù)合索引只要有一列含有NULL值,那么這一列對(duì)于此符合索引就是無(wú)效的,因此我們?cè)谠O(shè)計(jì)數(shù)據(jù)庫(kù)設(shè)計(jì)時(shí)不要讓字段的默認(rèn)值為NULL。
3,MySQL查詢(xún)只是用一個(gè)索引
如果where字句中使用了索引的話,那么order by中的列是不會(huì)使用索引的
4,like
like '%aaa%'不會(huì)使用索引而like "aaa%"可以使用索引
二、選擇索引的數(shù)據(jù)類(lèi)型
Mysql支持很多數(shù)據(jù)類(lèi)型,選擇合適的數(shù)據(jù)類(lèi)型存儲(chǔ)數(shù)據(jù)對(duì)性能有很大的影響。
(1)越小的數(shù)據(jù)類(lèi)型通常更好:越小的數(shù)據(jù)類(lèi)型通常在磁盤(pán)、內(nèi)存和cpu緩存中都需要更少的空間,處理起來(lái)更快。
(2)簡(jiǎn)單的數(shù)據(jù)類(lèi)型更好:整形數(shù)據(jù)比起字符,處理開(kāi)銷(xiāo)更小,因?yàn)樽址谋容^更復(fù)雜。在MySQL中,應(yīng)用內(nèi)置的日期和時(shí)間數(shù)據(jù)類(lèi)型,而不是字符串來(lái)存儲(chǔ)時(shí)間;以及用整形數(shù)據(jù)存儲(chǔ)IP地址。
(3)盡量避免NULL:應(yīng)該制定列為NOT NULL,除非你想存儲(chǔ)NULL。在MySQL中,含有空值的列很難進(jìn)行查詢(xún)優(yōu)化,因?yàn)樗麄兪沟盟饕⑺饕慕y(tǒng)計(jì)信息以及比較運(yùn)算更加復(fù)雜。
三、MySQL常見(jiàn)索引有:主鍵索引、唯一索引、普通索引、全文索引、組合索引
1,INDEX(普通索引):ALTER TABLE 'table_name' ADD INDEX index_name('col')
最基本的索引,沒(méi)有任何限制
2,UNIQUE(唯一索引):ALTER TABLE 'table_name' ADD UNIQUE('col')
與“普通索引”類(lèi)似,不同的就是:索引列的值必須唯一,但允許有空值。
3,PRIMARY KEY(主鍵索引):ALTER TABLE 'table_name' ADD PRIMARY KEY('col')
是一種特殊的唯一索引,不允許有空值。
4,FULLTEXT(全文索引):ALTER TABLE 'table_name' ADD FULLTEXT('col')
僅可用于MyISAM和InoDB,針對(duì)較大的數(shù)據(jù),生成全文索引很耗時(shí)耗空間
組合索引:ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3')
為了更多的提高mysql效率可建立組合索引,遵循“最左前綴”原則。創(chuàng)建復(fù)合索引應(yīng)該將最常用(頻率)做限制條件的列放在最左邊,一次遞減。組合索引最左字段用in是可以用到索引的。相當(dāng)于建立了col1,col1col2,col1col2col3三個(gè)索引
聚集索引和輔助索引
數(shù)據(jù)庫(kù)中的B+Tree索引可以分為聚集索引(clustered index)和輔助索引(secondary index)。上面的B+Tree示例圖在數(shù)據(jù)庫(kù)中的實(shí)現(xiàn)即為聚集索引,聚集索引的B+Tree中的葉子節(jié)點(diǎn)存放的是整張表的行記錄數(shù)據(jù)。輔助索引與聚集索引的區(qū)別在于輔助索引的葉子節(jié)點(diǎn)并不包含行記錄的全部數(shù)據(jù),而是存儲(chǔ)相應(yīng)行數(shù)據(jù)的聚集索引鍵,即主鍵。當(dāng)通過(guò)輔助索引來(lái)查詢(xún)數(shù)據(jù)時(shí),InnoDB存儲(chǔ)引擎會(huì)遍歷輔助索引找到主鍵,然后再通過(guò)主鍵在聚集索引中找到完整的行記錄數(shù)據(jù)
數(shù)據(jù)庫(kù)適合創(chuàng)建索引的規(guī)則如下:
表的主鍵,外鍵應(yīng)該創(chuàng)建索引;
數(shù)據(jù)量比較大的表應(yīng)該創(chuàng)建索引;
經(jīng)常需要和其他表建立連接,在連接字段應(yīng)該創(chuàng)建索引;
經(jīng)常出現(xiàn)在where子句中的字段,應(yīng)該創(chuàng)建索引。
數(shù)據(jù)庫(kù)不適合創(chuàng)建索引的情況:
比較大的文本字段或者長(zhǎng)度較長(zhǎng)的字段,不適合創(chuàng)建索引;
頻繁進(jìn)行數(shù)據(jù)操作的表,不適合創(chuàng)建過(guò)多的索引,因?yàn)轭~外維護(hù)索引表需要更多的開(kāi)銷(xiāo);
小型表(數(shù)據(jù)量低于300行)不要建立索引。
參考鏈接:
總結(jié)
以上是生活随笔為你收集整理的mysql 左连接 怎么走索引_数据库索引、左连接、右连接、等值连接的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 游戏《坦克世界》电脑配置
- 下一篇: linux select读取节点数据失败