2 mysql索引優(yōu)化分析

個(gè)人專題目錄


1. 性能下降SQL慢 執(zhí)行時(shí)間長(zhǎng) 等待時(shí)間長(zhǎng)

1.1 查詢語(yǔ)句寫(xiě)的爛

1.2 索引失效

單值

復(fù)合

1.3 關(guān)聯(lián)查詢太多join(設(shè)計(jì)缺陷或不得已的需求)

1.4 服務(wù)器調(diào)優(yōu)及各個(gè)參數(shù)設(shè)置(緩沖\線程數(shù)等)

2. 常見(jiàn)通用的join查詢

2.1 SQL執(zhí)行順序

手寫(xiě)

SELECT DISTINCT
    < select_list >
FROM
    < left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
    < where_condition >
GROUP BY
    < group_by_list >
HAVING
    < having_condition >
ORDER BY
    < order_by_condition >
LIMIT < limit_number >

機(jī)讀

FROM <left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>

總結(jié)

clip_image044.jpg

2.2 Join圖

clip_image046.jpg

2.3 建表SQL

2.4 7種Join

3. 索引簡(jiǎn)介

3.1 是什么

MySQL官方對(duì)索引的定義為:索引(Index)是幫助MySQL高校獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)俊性。 可以得到索引的本質(zhì):索引是數(shù)據(jù)結(jié)構(gòu)

  • 索引的目的在于提高查詢效率箍铭,可以類比字典。
  • 如果要查‘mysql’這個(gè)單詞,我們肯定需求定位到m字母,然后從上往下找到y(tǒng)字母,再找到sql.
  • 如果沒(méi)有索引,順序遍歷

你可以簡(jiǎn)單理解為"排好序的快速查找數(shù)據(jù)結(jié)構(gòu)"驳阎。

詳解(重要)

clip_image050.jpg

結(jié)論

數(shù)據(jù)本身之外,數(shù)據(jù)庫(kù)還維護(hù)著一個(gè)滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式指向數(shù)據(jù)馁蒂, 這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上實(shí)現(xiàn)高級(jí)查找算法,這種數(shù)據(jù)結(jié)構(gòu)就是索引呵晚。

一般來(lái)說(shuō)索引本身也很大,不可能全部存儲(chǔ)在內(nèi)存中沫屡,因此索引往往以文件形式存儲(chǔ)在硬盤(pán)上

我們平時(shí)所說(shuō)的索引饵隙,如果沒(méi)有特別指明,都是指B樹(shù)(多路搜索樹(shù)谁鳍,并不一定是二叉樹(shù))結(jié)構(gòu)組織的索引癞季。其中聚集索引,次要索引倘潜,覆蓋索引绷柒, 復(fù)合索引,前綴索引涮因,唯一索引默認(rèn)都是使用B+樹(shù)索引废睦,統(tǒng)稱索引。當(dāng)然,除了B+樹(shù)這種類型的索引之外养泡,還有哈希索引(hash index)等嗜湃。

3.2 優(yōu)勢(shì)

類似大學(xué)圖書(shū)館建書(shū)目索引,提高數(shù)據(jù)檢索效率澜掩,降低數(shù)據(jù)庫(kù)的IO成本

通過(guò)索引列對(duì)數(shù)據(jù)進(jìn)行排序购披,降低數(shù)據(jù)排序成本,降低了CPU的消耗

為什么要?jiǎng)?chuàng)建索引肩榕?這是因?yàn)楦斩福瑒?chuàng)建索引可以大大提高系統(tǒng)的查詢性能。

第一、通過(guò)創(chuàng)建唯一性索引筐乳,可以保證數(shù)據(jù)庫(kù)表中每一行數(shù)據(jù)的唯一性歌殃。

第二、可以大大加快 數(shù)據(jù)的檢索速度蝙云,這也是創(chuàng)建索引的最主要的原因氓皱。

第三、可以加速表和表之間的連接勃刨,特別是在實(shí)現(xiàn)數(shù)據(jù)的參考完整性方面特別有意義波材。

第四、在使用分組和排序子句進(jìn)行數(shù)據(jù)檢索時(shí)朵你,同樣可以顯著減少查詢中分組和排序的時(shí)間各聘。

第五揣非、通過(guò)使用索引抡医,可以在查詢的過(guò)程中,使用查詢優(yōu)化器早敬,提高系統(tǒng)的性能忌傻。

3.3 劣勢(shì)

實(shí)際上索引也是一張表,該表保存了主鍵和索引字段搞监,并指向?qū)嶓w表的記錄,所以索引列也是要占用空間的

雖然索引大大提高了查詢速度水孩,同時(shí)卻會(huì)降低更新表的速度,如果對(duì)表INSERT,UPDATE和DELETE。 因?yàn)楦卤頃r(shí)琐驴,MySQL不僅要不存數(shù)據(jù)俘种,還要保存一下索引文件每次更新添加了索引列的字段, 都會(huì)調(diào)整因?yàn)楦滤鶐?lái)的鍵值變化后的索引信息

索引只是提高效率的一個(gè)因素绝淡,如果你的MySQL有大數(shù)據(jù)量的表宙刘,就需要花時(shí)間研究建立優(yōu)秀的索引,或優(yōu)化查詢語(yǔ)句

3.4 mysql索引分類

單值索引

即一個(gè)索引只包含單個(gè)列牢酵,一個(gè)表可以有多個(gè)單列索引

建議一張表索引不要超過(guò)5個(gè)

優(yōu)先考慮復(fù)合索引

唯一索引

索引列的值必須唯一悬包,但允許有空值

復(fù)合索引

即一個(gè)索引包含多個(gè)列

基本語(yǔ)法

創(chuàng)建

CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));

如果是CHAR,VARCHAR類型,length可以小于字段實(shí)際長(zhǎng)度馍乙; 如果是BLOB和TEXT類型布近,必須指定length。

ALTER mytable ADD [UNIQUE] INDEX [indexName] ON(columnname(length));

刪除

DROP INDEX [indexName] ON mytable;

查看

SHOW INDEX FROM table_name\G

使用ALTER命令

clip_image052.jpg

3.5 mysql索引結(jié)構(gòu)

BTree索引

B-Tree索引丝格,顧名思義撑瞧,就是所有的索引節(jié)點(diǎn)都按照balance tree的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)。B-tree結(jié)構(gòu)可以顯著減少定位記錄時(shí)所經(jīng)歷的中間過(guò)程显蝌,從而加快存取速度预伺。

B-tree中,每個(gè)結(jié)點(diǎn)包含:

1、本結(jié)點(diǎn)所含關(guān)鍵字的個(gè)數(shù)扭屁;

2算谈、指向父結(jié)點(diǎn)的指針;

3料滥、關(guān)鍵字然眼;

4、指向子結(jié)點(diǎn)的指針葵腹;

對(duì)于一棵m階B-tree高每,每個(gè)結(jié)點(diǎn)至多可以擁有m個(gè)子結(jié)點(diǎn)。各結(jié)點(diǎn)的關(guān)鍵字和可以擁有的子結(jié)點(diǎn)數(shù)都有限制践宴,規(guī)定m階B-tree中鲸匿,根結(jié)點(diǎn)至少有2個(gè)子結(jié)點(diǎn),除非根結(jié)點(diǎn)為葉子節(jié)點(diǎn)阻肩,相應(yīng)的带欢,根結(jié)點(diǎn)中關(guān)鍵字的個(gè)數(shù)為1m-1;非根結(jié)點(diǎn)至少有[m/2]([]烤惊,向上取整)個(gè)子結(jié)點(diǎn)乔煞,相應(yīng)的,關(guān)鍵字個(gè)數(shù)為[m/2]-1m-1柒室。

B-tree有以下特性:

1渡贾、關(guān)鍵字集合分布在整棵樹(shù)中;

2雄右、任何一個(gè)關(guān)鍵字出現(xiàn)且只出現(xiàn)在一個(gè)結(jié)點(diǎn)中空骚;

3、搜索有可能在非葉子結(jié)點(diǎn)結(jié)束擂仍;

4囤屹、其搜索性能等價(jià)于在關(guān)鍵字全集內(nèi)做一次二分查找;

5防楷、自動(dòng)層次控制牺丙;

由于限制了除根結(jié)點(diǎn)以外的非葉子結(jié)點(diǎn),至少含有M/2個(gè)兒子复局,確保了結(jié)點(diǎn)的至少利用率冲簿,其最低搜索性能為:

clip_image004.jpg

其中,M為設(shè)定的非葉子結(jié)點(diǎn)最多子樹(shù)個(gè)數(shù)亿昏,N為關(guān)鍵字總數(shù)峦剔;

所以B-樹(shù)的性能總是等價(jià)于二分查找(與M值無(wú)關(guān)),也就沒(méi)有B樹(shù)平衡的問(wèn)題角钩;

由于M/2的限制吝沫,在插入結(jié)點(diǎn)時(shí)呻澜,如果結(jié)點(diǎn)已滿,需要將結(jié)點(diǎn)分裂為兩個(gè)各占M/2的結(jié)點(diǎn)惨险;刪除結(jié)點(diǎn)時(shí)羹幸,需將兩個(gè)不足M/2的兄弟結(jié)點(diǎn)合并。

clip_image054.jpg

初始化介紹

一顆b+樹(shù)辫愉,淺藍(lán)色的塊我們稱為一個(gè)磁盤(pán)塊栅受,可以看到每個(gè)磁盤(pán)塊包含幾個(gè)數(shù)據(jù)項(xiàng)(深藍(lán)色表示)和指針(黃色表示),如磁盤(pán)塊1包含數(shù)據(jù)項(xiàng)17和35恭朗,包含指針P1屏镊、P2、P3.

P1表示小于17的磁盤(pán)塊痰腮,P2表示在17到35之間的磁盤(pán)塊而芥,P3表示大于35的磁盤(pán)塊。

真實(shí)的數(shù)據(jù)存在于葉子節(jié)點(diǎn)膀值,即3棍丐,5,9虫腋,10骄酗,13稀余,15悦冀,28,29睛琳,36...

非葉子節(jié)點(diǎn)只不存儲(chǔ)真實(shí)的數(shù)據(jù)盒蟆,只存儲(chǔ)引擎搜索方向的數(shù)據(jù)項(xiàng),如17师骗、35并不是真實(shí)存于數(shù)據(jù)表中历等。

【查找過(guò)程】

如果要查找數(shù)據(jù)項(xiàng)29,那么首先會(huì)把磁盤(pán)塊1由磁盤(pán)加載到內(nèi)存辟癌,此時(shí)發(fā)生一次IO寒屯,在內(nèi)存中用二分查找確實(shí)29在17和35之間,鎖定磁盤(pán)塊1的P2指針黍少,內(nèi)存時(shí)間因?yàn)榉浅6?相比磁盤(pán)的IO)可以忽略不計(jì)寡夹,通過(guò)磁盤(pán)塊1的P2指針的磁盤(pán)地址把磁盤(pán)塊3由磁盤(pán)加載到內(nèi)存,發(fā)生第二次IO厂置,29在26和30之間菩掏,鎖定磁盤(pán)塊3的P2指針,通過(guò)指針加載磁盤(pán)塊8到內(nèi)存昵济,發(fā)生第三次IO智绸,同時(shí)內(nèi)存中做二分查找找到29野揪,結(jié)束查詢,總計(jì)三次IO瞧栗。

Btree索引(或Balanced Tree)斯稳,是一種很普遍的數(shù)據(jù)庫(kù)索引結(jié)構(gòu),oracle默認(rèn)的索引類型(本文也主要依據(jù)oracle來(lái)講)迹恐。其特點(diǎn)是定位高效平挑、利用率高、自我平衡系草,特別適用于高基數(shù)字段通熄,定位單條或小范圍數(shù)據(jù)非常高效。理論上找都,使用Btree在億條數(shù)據(jù)與100條數(shù)據(jù)中定位記錄的花銷相同唇辨。

數(shù)據(jù)結(jié)構(gòu)利用率高、定位高效

Btree索引的數(shù)據(jù)結(jié)構(gòu)如下:

clip_image058.jpg

結(jié)構(gòu)看起來(lái)Btree索引與Binary Tree相似能耻,但在細(xì)節(jié)上有所不同赏枚,上圖中用不同顏色的標(biāo)示出了Btree索引的幾個(gè)主要特點(diǎn):

樹(shù)形結(jié)構(gòu):由根節(jié)(root)、分支(branches)晓猛、葉(leaves)三級(jí)節(jié)點(diǎn)組成饿幅,其中分支節(jié)點(diǎn)可以有多層。

多分支結(jié)構(gòu):與binary tree不相同的是戒职,btree索引中單root/branch可以有多個(gè)子節(jié)點(diǎn)(超過(guò)2個(gè))栗恩。

雙向鏈表:整個(gè)葉子節(jié)點(diǎn)部分是一個(gè)雙向鏈表(后面會(huì)描述這個(gè)設(shè)計(jì)的作用)

單個(gè)數(shù)據(jù)塊中包括多條索引記錄

這里先把幾個(gè)特點(diǎn)羅列出來(lái),后面會(huì)說(shuō)到各自的作用洪燥。

結(jié)構(gòu)上Btree與Binary Tree的區(qū)別磕秤,在于binary中每節(jié)點(diǎn)代表一個(gè)數(shù)值,而balanced中root和Btree節(jié)點(diǎn)中記錄了多條”值范圍”條目(如:[60-70][70-80])捧韵,這些”值范圍”條目分別指向在其范圍內(nèi)的葉子節(jié)點(diǎn)市咆。既root與branch可以有多個(gè)分支,而不一定是兩個(gè)再来,對(duì)數(shù)據(jù)塊的利用率更高蒙兰。

在Leaf節(jié)點(diǎn)中,同樣也是存放了多條索引記錄芒篷,這些記錄就是具體的索引列值搜变,和與其對(duì)應(yīng)的rowid。另外梭伐,在葉節(jié)點(diǎn)層上痹雅,所有的節(jié)點(diǎn)在組成了一個(gè)雙向鏈表。

了解基本結(jié)構(gòu)后糊识,下圖展示定位數(shù)值82的過(guò)程:

clip_image060.jpg

演算如下:

讀取root節(jié)點(diǎn)绩社,判斷82大于在0-120之間摔蓝,走左邊分支。

讀取左邊branch節(jié)點(diǎn)愉耙,判斷82大于80且小于等于120贮尉,走右邊分支。

讀取右邊leaf節(jié)點(diǎn)朴沿,在該節(jié)點(diǎn)中找到數(shù)據(jù)82及對(duì)應(yīng)的rowid

使用rowid去物理表中讀取記錄數(shù)據(jù)塊(如果是count或者只select rowid猜谚,則最后一次讀取不需要)

在整個(gè)索引定位過(guò)程中,數(shù)據(jù)塊的讀取只有3次赌渣。既三次I/O后定位到rowid魏铅。

而由于Btree索引對(duì)結(jié)構(gòu)的利用率很高,定位高效坚芜。當(dāng)1千萬(wàn)條數(shù)據(jù)時(shí)览芳,Btree索引也是三層結(jié)構(gòu)(依稀記得億級(jí)數(shù)據(jù)才是3層與4層的分水嶺)。定位記錄仍只需要三次I/O鸿竖,這便是開(kāi)頭所說(shuō)的沧竟,100條數(shù)據(jù)和1千萬(wàn)條數(shù)據(jù)的定位,在btree索引中的花銷是一樣的缚忧。

平衡擴(kuò)張

除了利用率高悟泵、定位高效外,Btree的另一個(gè)特點(diǎn)是能夠永遠(yuǎn)保持平衡闪水,這與它的擴(kuò)張方式有關(guān)糕非。(unbalanced和hotspot是兩類問(wèn)題,之前我一直混在一起)敦第,先描述下Btree索引的擴(kuò)張方式:

新建一個(gè)索引峰弹,索引上只會(huì)有一個(gè)leaf節(jié)點(diǎn),取名為Node A芜果,不斷的向這個(gè)leaf節(jié)點(diǎn)中插入數(shù)據(jù)后,直到這個(gè)節(jié)點(diǎn)滿融师,這個(gè)過(guò)程如下圖(綠色表示新建/空閑狀態(tài)右钾,紅色表示節(jié)點(diǎn)沒(méi)有空余空間):

clip_image062.jpg

當(dāng)Node A滿之后,我們?cè)傧虮碇胁迦胍粭l記錄旱爆,此時(shí)索引就需要做拆分處理:會(huì)新分配兩個(gè)數(shù)據(jù)塊NodeB & C舀射,如果新插入的值,大于當(dāng)前最大值怀伦,則將Node A中的值全部插入Node B中脆烟,將新插入的值放到Node C中;否則按照5-5比例房待,將已有數(shù)據(jù)分別插入到NodeB與C中邢羔。

無(wú)論采用哪種分割方式驼抹,之前的leaf節(jié)點(diǎn)A,將變成一個(gè)root節(jié)點(diǎn)拜鹤,保存兩個(gè)范圍條目框冀,指向B與C,結(jié)構(gòu)如下圖(按第一種拆分形式):

clip_image064.jpg

當(dāng)Node C滿之后敏簿,此時(shí) Node A仍有空余空間存放條目明也,所以不需要再拆分,而只是新分配一個(gè)數(shù)據(jù)塊Node D惯裕,將在Node A中創(chuàng)建指定到Node D的條目:

clip_image066.jpg

如果當(dāng)根節(jié)點(diǎn)Node A也滿了温数,則需要進(jìn)一步拆分:新建Node E&F&G,將Node A中范圍條目拆分到E&F兩個(gè)節(jié)點(diǎn)中蜻势,并建立E&F到BCD節(jié)點(diǎn)的關(guān)聯(lián)帆吻,向Node G插入索引值。此時(shí)E&F為branch節(jié)點(diǎn)咙边,G為leaf節(jié)點(diǎn)猜煮,A為Root節(jié)點(diǎn):

clip_image068.jpg

在整個(gè)擴(kuò)張過(guò)程中,Btree自身總能保持平衡败许,Leaf節(jié)點(diǎn)的深度能一直保持一致王带。

實(shí)際應(yīng)用中的一些問(wèn)題

前面說(shuō)完了Btree索引的結(jié)構(gòu)與擴(kuò)張邏輯,接下來(lái)講一些Btree索引在應(yīng)用中的一些問(wèn)題:

單一方向擴(kuò)展引起的索引競(jìng)爭(zhēng)(Index Contention)

若索引列使用sequence或者timestamp這類只增不減的數(shù)據(jù)類型市殷。這種情況下Btree索引的增長(zhǎng)方向總是不變的愕撰,不斷的向右邊擴(kuò)展,因?yàn)樾虏迦氲闹涤肋h(yuǎn)是最大的醋寝。

當(dāng)一個(gè)最大值插入到leaf block中后搞挣,leaf block要向上傳播,通知上層節(jié)點(diǎn)更新所對(duì)應(yīng)的“值范圍”條目中的最大值音羞,因此所有靠右邊的block(從leaf 到branch甚至root)都需要做更新操作囱桨,并且可能因?yàn)閴K寫(xiě)滿后執(zhí)行塊拆分。

如果并發(fā)插入多個(gè)最大值嗅绰,則最右邊索引數(shù)據(jù)塊的的更新與拆分都會(huì)存在爭(zhēng)搶舍肠,影響效率。在AWR報(bào)告中可以通過(guò)檢測(cè)enq: TX – index contention事件的時(shí)間來(lái)評(píng)估爭(zhēng)搶的影響窘面。解決此類問(wèn)題可以使用Reverse Index解決翠语,不過(guò)會(huì)帶來(lái)新的問(wèn)題。

Index Browning 索引枯萎(不知道該怎么翻譯這個(gè)名詞财边,就是指leaves節(jié)點(diǎn)”死”了肌括,樹(shù)枯萎了)

其實(shí)oracle針對(duì)這個(gè)問(wèn)題有優(yōu)化機(jī)制,但優(yōu)化的不徹底酣难,所以還是要拿出來(lái)的說(shuō)谍夭。

我們知道當(dāng)表中的數(shù)據(jù)刪除后黑滴,索引上對(duì)應(yīng)的索引值是不會(huì)刪除的,特別是在一性次刪除大批量數(shù)據(jù)后慧库,會(huì)造成大量的dead leaf掛到索引樹(shù)上跷跪。考慮以下示例齐板,如果表100以上的數(shù)據(jù)會(huì)部被刪除了吵瞻,但這些記錄仍在索引中存在,此時(shí)若對(duì)該列取max():

clip_image070.jpg

通過(guò)與之前相同演算甘磨,找到了索引樹(shù)上最大的數(shù)據(jù)塊橡羞,按照記錄最大的值應(yīng)該在這里,但發(fā)現(xiàn)這數(shù)據(jù)塊里的數(shù)據(jù)已經(jīng)被清空了济舆,與是利用Btree索引的另一個(gè)特點(diǎn):leaves節(jié)點(diǎn)是一個(gè)雙向列表卿泽,若數(shù)據(jù)沒(méi)有找到就去臨近的一個(gè)數(shù)據(jù)塊中看看,在這個(gè)數(shù)據(jù)塊中發(fā)現(xiàn)了最大值99滋觉。

在計(jì)算最大值的過(guò)程中签夭,這次的定位多加載了一個(gè)數(shù)據(jù)塊,再極端的情況下椎侠,大批量的數(shù)據(jù)被刪除第租,就會(huì)造成大量訪問(wèn)這些dead leaves。

針對(duì)這個(gè)問(wèn)題的一般解決辦法是重建索引我纪,但記住! 重建索引并不是最優(yōu)方案慎宾,詳細(xì)原因可以看看這。使用coalesce語(yǔ)句來(lái)整理這些dead leaves到freelist中浅悉,就可以避免這些問(wèn)題趟据。理論上oracle中這步操作是可以自動(dòng)完成的,但在實(shí)際中一次性大量刪除數(shù)據(jù)后术健,oracle在短時(shí)間內(nèi)是反應(yīng)不過(guò)來(lái)的汹碱。

Hash索引,了解

full-text全文索引苛坚,F(xiàn)ull-text索引就是我們常說(shuō)的全文索引比被,他的存儲(chǔ)結(jié)構(gòu)也是b-tree。主要是為了解決在我們需要用like查詢的低效問(wèn)題泼舱。只能解決’xxx%’的like查詢。如:字段數(shù)據(jù)為ABCDE枷莉,索引建立為- A娇昙、AB、ABC笤妙、ABCD冒掌、ABCDE五個(gè)噪裕。

R-Tree索引,了解

3.6 哪些情況需要?jiǎng)?chuàng)建索引

1.主鍵自動(dòng)建立唯一索引

2.頻繁作為查詢的條件的字段應(yīng)該創(chuàng)建索引

3.查詢中與其他表關(guān)聯(lián)的字段股毫,外鍵關(guān)系建立索引

4.頻繁更新的字段不適合創(chuàng)建索引

因?yàn)槊看胃虏粏螁问歉铝擞涗涍€會(huì)更新索引膳音,加重IO負(fù)擔(dān)

5.Where條件里用不到的字段不創(chuàng)建索引

6.單間/組合索引的選擇問(wèn)題,who铃诬?(在高并發(fā)下傾向創(chuàng)建組合索引)

7.查詢中排序的字段祭陷,排序字段若通過(guò)索引去訪問(wèn)將大大提高排序的速度

8.查詢中統(tǒng)計(jì)或者分組字段

建立索引,一般按照select的where條件來(lái)建立趣席,比如: select的條件是where f1 and f2兵志,那么如果我們?cè)谧侄蝔1或字段f2上建立索引是沒(méi)有用的,只有在字段f1和f2上同時(shí)建立索引才有用等宣肚。

3.7 哪些情況不要?jiǎng)?chuàng)建索引

1.表記錄太少

2.經(jīng)常增刪改的表,這是因?yàn)橄牒保薷男阅芎蜋z索性能是互相矛盾的。當(dāng)增加索引時(shí)霉涨,會(huì)提高檢索性能按价,但是會(huì)降低修改性能。當(dāng)減少索引時(shí)笙瑟,會(huì)提高修改性能楼镐,降低檢索性能。因此逮走,當(dāng)修改性能遠(yuǎn)遠(yuǎn)大于檢索性能時(shí)鸠蚪,不應(yīng)該創(chuàng)建索引。

3.數(shù)據(jù)重復(fù)且分布平均的表字段师溅,因此應(yīng)該只為經(jīng)常查詢和經(jīng)常排序的數(shù)據(jù)列建立索引茅信。 注意,如果某個(gè)數(shù)據(jù)列包含許多重復(fù)的內(nèi)容墓臭,為它建立索引就沒(méi)有太大的實(shí)際效果蘸鲸。

假如一個(gè)表有10萬(wàn)行記錄,有一個(gè)字段A只胡T和F兩種值窿锉,且每個(gè)值的分布概率大約為50%酌摇,那么對(duì)這種表A字段建索引一般不會(huì)提高數(shù)據(jù)庫(kù)的查詢速度。

索引的選擇性是指索引列中不同值的數(shù)據(jù)與不用跟記錄數(shù)的比嗡载。如果一個(gè)表中有2000條記錄采郎,表索引列有1980個(gè)不同的值镐作,那么這個(gè)索引的選擇性是1980/2000=0.99。一個(gè)索引的選擇性越接近于1,這個(gè)索引的效率就越高火俄。

  1. 對(duì)于那些定義為text, image和bit數(shù)據(jù)類型的列不應(yīng)該增加索引。這是因?yàn)椋@些列的數(shù)據(jù)量要么相當(dāng)大,要么取值很少享幽。

3.8 索引管理

普通索引

這是最基本的索引,它沒(méi)有任何限制MyIASM中默認(rèn)的BTREE類型的索引拾弃,也是我們大多數(shù)情況下用到的索引值桩。

創(chuàng)建索引
CREATE  INDEX  index_name  ON  table_name (column(length))
ALTER TABLE table_name ADD INDEX index_name (column(length))
CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id) , INDEX  index_name (title(5)))
查看索引
SHOW  INDEX  FROM  [table_name]
SHOW  KEYS  FROM  [table_name]   # 只在MySQL中可以使用keys關(guān)鍵字。
刪除索引
DROP INDEX  index_name  ON talbe_name
ALTER TABLE  table_name  DROP INDEX  index_name
ALTER TABLE  table_name  DROP PRIMARY KEY

唯一索引

與普通索引類似豪椿,不同的就是:索引列的值必須唯一奔坟,但允許有空值(注意和主鍵不同)。如果是組合索引砂碉,則列值的組合必須唯一蛀蜜,創(chuàng)建方法和普通索引類似

創(chuàng)建索引
CREATE UNIQUE INDEX index_name  ON table_name (column(length))
ALTER TABLE table_name ADD UNIQUE index_name  (column(length))
CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id) ,  UNIQUE  index_name (title(length)))

全文索引(FULLTEXT)

MySQL從3.23.23版開(kāi)始支持全文索引和全文檢索,F(xiàn)ULLTEXT索引僅可用于 MyISAM 表增蹭;他們可以從CHAR滴某、VARCHAR或TEXT列中作為CREATE TABLE語(yǔ)句的一部分被創(chuàng)建,或是隨后使用ALTER TABLE 或CREATE INDEX被添加滋迈。

對(duì)于較大的數(shù)據(jù)集霎奢,將你的資料輸入一個(gè)沒(méi)有FULLTEXT索引的表中,然后創(chuàng)建索引饼灿,其速度比把資料輸入現(xiàn)有FULLTEXT索引的速度更為快幕侠。不過(guò)切記對(duì)于大容量的數(shù)據(jù)表,生成全文索引是一個(gè)非常消耗時(shí)間非常消耗硬盤(pán)空間的做法碍彭。

創(chuàng)建索引
CREATE FULLTEXT INDEX index_name ON table_name(column(length))
ALTER TABLE table_name ADD FULLTEXT index_name( column)
CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id) ,  FULLTEXT  index_name (title))

組合索引(最左前綴)

CREATE TABLE article(id int not null, title varchar(255), time date);

平時(shí)用的SQL查詢語(yǔ)句一般都有比較多的限制條件晤硕,所以為了進(jìn)一步榨取MySQL的效率,就要考慮建立組合索引庇忌。例如上表中針對(duì)title和time建立一個(gè)組合索引:ALTER TABLE article ADD INDEX index_title_time (title(50),time(10))舞箍。建立這樣的組合索引,其實(shí)是相當(dāng)于分別建立了下面兩組組合索引:

–title,time

–title

為什么沒(méi)有time這樣的組合索引呢皆疹?這是因?yàn)镸ySQL組合索引“最左前綴”的結(jié)果疏橄。簡(jiǎn)單的理解就是只從最左面的開(kāi)始組合。并不是只要包含這兩列的查詢都會(huì)用到該組合索引略就,如下面的幾個(gè)SQL所示:

1捎迫,使用到上面的索引

SELECT * FROM article WHERE title='測(cè)試' AND time=1234567890;

SELECT * FROM article WHERE title='測(cè)試';

2,不使用上面的索引

SELECT * FROM article WHERE time=1234567890;

創(chuàng)建索引

CREATE INDEX index_name ON table_name (column_list)

4. 性能分析

4.1 MySQL Query Optimizer

  • Mysql中有專門(mén)負(fù)責(zé)優(yōu)化的SELECT語(yǔ)句的優(yōu)化器模塊表牢,主要功能:通過(guò)計(jì)算分析系統(tǒng)中收集到的統(tǒng)計(jì)信息窄绒,為客戶端請(qǐng)求的Query提供他認(rèn)為最優(yōu)的執(zhí)行計(jì)劃(他認(rèn)為最優(yōu)的數(shù)據(jù)檢索方式,但不見(jiàn)得是DBA認(rèn)為最優(yōu)的崔兴,這部分最耗費(fèi)時(shí)間)
  • 當(dāng)客戶端向MYSQL請(qǐng)求一條Query颗祝,命令解析器模塊完成請(qǐng)求分類浊闪,區(qū)別出是SELECT并轉(zhuǎn)發(fā)給Mysql Query Optimizer恼布,MySQL Query Optimizer 首先會(huì)對(duì)整條Query進(jìn)行優(yōu)化螺戳,處理掉一些常量表達(dá)式的預(yù)算,直接換算成常量值折汞。并對(duì)Query中的查詢條件進(jìn)行簡(jiǎn)化和轉(zhuǎn)換倔幼,如去掉一些無(wú)用或顯而易見(jiàn)的條件、結(jié)構(gòu)調(diào)等爽待。然后分析Query中的Hint信息(如果有)损同,看顯示Hint信息是否可以完全確定該Query的執(zhí)行計(jì)劃。如果沒(méi)有Hint或Hint信息還不足以完全確定執(zhí)行計(jì)劃鸟款,則會(huì)讀取所涉及對(duì)象的統(tǒng)計(jì)信息膏燃,根據(jù)Query進(jìn)行寫(xiě)相應(yīng)的計(jì)算分析,然后再得出最后的執(zhí)行計(jì)劃何什。

4.2 MySQL常見(jiàn)瓶頸

CPU:CPU在飽和的時(shí)候一般發(fā)生在數(shù)據(jù)裝入在內(nèi)存或從磁盤(pán)上讀取數(shù)據(jù)時(shí)候

IO:磁盤(pán)I/O瓶頸發(fā)生在裝入數(shù)據(jù)遠(yuǎn)大于內(nèi)存容量時(shí)

服務(wù)器硬件的性能瓶頸:top,free,iostat和vmstat來(lái)查看系統(tǒng)的性能狀態(tài)

4.3 Explain

是什么(查看執(zhí)行計(jì)劃)

使用EXPLAIN關(guān)鍵字可以模擬優(yōu)化器執(zhí)行SQL語(yǔ)句组哩,從而知道MySQL是 如何處理你的SQL語(yǔ)句的。分析你的查詢語(yǔ)句或是結(jié)構(gòu)的性能瓶頸

官網(wǎng)介紹

能干嘛

表的讀取順序

數(shù)據(jù)讀取操作的操作類型

哪些索引可以使用

哪些索引被實(shí)際使用

表之間的引用

每張表有多少行被優(yōu)化器查詢

怎么玩

Explain+SQL語(yǔ)句

執(zhí)行計(jì)劃包含的信息

+----+-------------+-------+------+---------------+------+---------+------+------+-------
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------

各個(gè)字段解釋

id

select查詢的序列號(hào)处渣,包含一組數(shù)字伶贰,表示查詢中執(zhí)行select子句或操作表的順序

三種情況

id相同,執(zhí)行順序由上至下

clip_image078.jpg

id不同罐栈,如果是子查詢黍衙,id的序號(hào)會(huì)遞增,id值越大優(yōu)先級(jí)越高荠诬,越先被執(zhí)行

clip_image080.jpg

id相同不同琅翻,同時(shí)存在

clip_image082.jpg

select_type:查詢的類型,主要用于區(qū)別 普通查詢柑贞、聯(lián)合查詢方椎、子查詢等的復(fù)雜查詢

類型名稱 描述
SIMPLE 簡(jiǎn)單的select查詢,查詢中不包含子查詢或者UNION
PRIMARY 查詢中若包含任何復(fù)雜的子部分凌外,最外層查詢則被標(biāo)記為
SUBQUERY 在SELECT或者WHERE列表中包含了子查詢
DERIVED 在FROM列表中包含的子查詢被標(biāo)記為DERIVED(衍生) MySQL會(huì)遞歸執(zhí)行這些子查詢辩尊,把結(jié)果放在臨時(shí)表里。
UNION 若第二個(gè)SELECT出現(xiàn)在UNION之后康辑,則被標(biāo)記為UNION; 若UNION包含在FROM子句的子查詢中摄欲,外層SELECT將被標(biāo)記為:DERIVED
UNION RESULT 從UNION表獲取結(jié)果的SELECT

table:顯示這一行的數(shù)據(jù)是關(guān)于哪張表的

type

ALL index range ref eq_ref const,system NULL

訪問(wèn)類型排列

type顯示的是訪問(wèn)類型,是較為重要的一個(gè)指標(biāo)疮薇,結(jié)果值從最好到最壞依次是:
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL

顯示查詢使用了何種類型 從最好到最差依次是:
system>const>eq_ref>ref>range>index>ALL
一般來(lái)說(shuō)胸墙,得保證查詢至少達(dá)到range級(jí)別,最好能達(dá)到ref.

system

表只有一行記錄(等于系統(tǒng)表)按咒,這是const類型的特例迟隅,平時(shí)不會(huì)出現(xiàn),這個(gè)也可以忽略不計(jì)

const

clip_image089.jpg

表示通過(guò)索引一次就找到了,const用于比較primary key或者unique索引智袭。因?yàn)橹黄ヅ湟恍袛?shù)據(jù)奔缠,所以很快。如將主鍵至于where列表中吼野,MySQL就能將該查詢轉(zhuǎn)換為一個(gè)常量

eq_ref

clip_image091.jpg

唯一性索引校哎,對(duì)于每個(gè)索引鍵,表中只有一條記錄與之匹配瞳步,常見(jiàn)于主鍵或唯一索引掃描

ref

clip_image093.jpg

非唯一索引掃描闷哆,返回匹配某個(gè)單獨(dú)值的所有行。 本質(zhì)上也是一種索引訪問(wèn)单起,它返回所有匹配某個(gè)單獨(dú)值的行抱怔,然而, 它可能會(huì)找到多個(gè)符合條件的行嘀倒,所以他應(yīng)該屬于查找和掃描的混合體

range

clip_image095.jpg

只檢索給定范圍的行屈留,使用一個(gè)索引來(lái)選擇行。key列顯示使用了哪個(gè)索引 一般就是在你的where語(yǔ)句中出現(xiàn)了between括儒、<绕沈、>、in等的查詢 這種范圍掃描索引掃描比全表掃描要好帮寻,因?yàn)樗恍枰_(kāi)始索引的某一點(diǎn)乍狐,而結(jié)束語(yǔ)另一點(diǎn),不用掃描全部索引

index

clip_image097.jpg

Full Index Scan,index與ALL區(qū)別為index類型只遍歷索引樹(shù)固逗。這通常比ALL快浅蚪,因?yàn)樗饕募ǔ1葦?shù)據(jù)文件小。 (也就是說(shuō)雖然all和index都是讀全表烫罩,但index是從索引中讀取的惜傲,而all是從硬盤(pán)中讀的)

all

clip_image099.jpg

FullTable Scan,將遍歷全表以找到匹配的行

備注:

一般來(lái)說(shuō),得保證查詢只是達(dá)到range級(jí)別贝攒,最好達(dá)到ref

possible_keys

顯示可能應(yīng)用在這張表中的索引,一個(gè)或多個(gè)盗誊。 查詢涉及的字段上若存在索引,則該索引將被列出隘弊,但不一定被查詢實(shí)際使用

key

實(shí)際使用的索引哈踱。如果為null則沒(méi)有使用索引

查詢中若使用了覆蓋索引,則索引和查詢的select字段重疊

參閱: 3.USING index

key_len

表示索引中使用的字節(jié)數(shù)梨熙,可通過(guò)該列計(jì)算查詢中使用的索引的長(zhǎng)度开镣。在不損失精確性的情況下,長(zhǎng)度越短越好

key_len顯示的值為索引最大可能長(zhǎng)度咽扇,并非實(shí)際使用長(zhǎng)度邪财,即key_len是根據(jù)表定義計(jì)算而得陕壹,不是通過(guò)表內(nèi)檢索出的

clip_image101.jpg

ref

顯示索引那一列被使用了,如果可能的話树埠,是一個(gè)常數(shù)糠馆。那些列或常量被用于查找索引列上的值

clip_image103.jpg

rows

clip_image105.jpg

根據(jù)表統(tǒng)計(jì)信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數(shù)

越少越好

Extra

包含不適合在其他列中顯示但十分重要的額外信息

1.Using filesort

clip_image107.jpg

說(shuō)明mysql會(huì)對(duì)數(shù)據(jù)使用一個(gè)外部的索引排序弥奸,而不是按照表內(nèi)的索引順序進(jìn)行讀取榨惠。 MySQL中無(wú)法利用索引完成排序操作成為“文件排序”

2.Using temporary

clip_image109.jpg

使用了臨時(shí)表保存中間結(jié)果,MySQL在對(duì)查詢結(jié)果排序時(shí)使用臨時(shí)表盛霎。常見(jiàn)于排序order by 和分組查詢 group by

3.USING index

clip_image111.jpg

表示相應(yīng)的select操作中使用了覆蓋索引(Coveing Index),避免訪問(wèn)了表的數(shù)據(jù)行,效率不錯(cuò)耽装! 如果同時(shí)出現(xiàn)using where愤炸,表明索引被用來(lái)執(zhí)行索引鍵值的查找; 如果沒(méi)有同時(shí)出現(xiàn)using where掉奄,表面索引用來(lái)讀取數(shù)據(jù)而非執(zhí)行查找動(dòng)作规个。

覆蓋索引(Covering Index)

  • 覆蓋索引(Convering Index),一說(shuō)為索引覆蓋姓建。
  • 理解方式一:就是select的數(shù)據(jù)列只用從索引中就能夠取得诞仓,不必讀取數(shù)據(jù)行,Mysql可以利用索引返回select列表中的字段速兔,而不必根據(jù)索引再次讀取數(shù)據(jù)文件墅拭,換句話說(shuō)查詢表要被所建的索引覆蓋。
  • 理解方式二:索引是高效找到行的一個(gè)方法涣狗,但是一般數(shù)據(jù)庫(kù)也能使用索引找到一個(gè)列的數(shù)據(jù)谍婉,因此它不必讀取整個(gè)行。畢竟索引葉子節(jié)點(diǎn)存儲(chǔ)了它的索引的數(shù)據(jù);當(dāng)能通過(guò)讀取索引就可以得到想要的數(shù)據(jù)镀钓,那就不需要讀取行了穗熬。一個(gè)索引包含了(或覆蓋了)滿足查詢結(jié)果的數(shù)據(jù)就叫覆蓋索引。
  • 注意:如果要使用覆蓋索引丁溅,一定要注意select列表中只取出需要的列唤蔗,不能select *,因?yàn)槿绻麑⑺凶侄我黄鹱鏊饕龝?huì)導(dǎo)致索引文件過(guò)大,查詢性能下降窟赏。

4.Using where

表面使用了where過(guò)濾

5.using join buffer

使用了連接緩存

6.impossible where

clip_image115.jpg

where子句的值總是false妓柜,不能用來(lái)獲取任何元組

7.select tables optimized away

在沒(méi)有GROUPBY子句的情況下,基于索引優(yōu)化MIN/MAX操作或者 對(duì)于MyISAM存儲(chǔ)引擎優(yōu)化COUNT(*)操作饰序,不必等到執(zhí)行階段再進(jìn)行計(jì)算领虹, 查詢執(zhí)行計(jì)劃生成的階段即完成優(yōu)化。

8.distinct

優(yōu)化distinct求豫,在找到第一匹配的元組后即停止找同樣值的工作

熱身Case

clip_image117.jpg
clip_image119.jpg

5. 索引優(yōu)化

索引不會(huì)包含有NULL值的列

只要列中包含有NULL值都將不會(huì)被包含在索引中塌衰,組合索引中只要有一列含有NULL值诉稍,那么這一列對(duì)于此組合索引就是無(wú)效的。所以我們?cè)跀?shù)據(jù)庫(kù)設(shè)計(jì)時(shí)不要讓字段的默認(rèn)值為NULL最疆。create table table_name(c1 varchar(32) default ‘0’)

使用短索引

對(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操作。

CREATE INDEX index_name ON table_name (column(length))

索引列排序

MySQL查詢只使用一個(gè)索引舔涎,因此如果where子句中已經(jīng)使用了索引的話笼踩,那么order by中的列是不會(huì)使用索引的。因此數(shù)據(jù)庫(kù)默認(rèn)排序可以符合要求的情況下不要使用排序操作亡嫌;盡量不要包含多個(gè)列的排序嚎于,如果需要最好給這些列創(chuàng)建復(fù)合索引。

like語(yǔ)句操作

一般情況下不鼓勵(lì)使用like操作挟冠,如果非使用不可于购,如何使用也是一個(gè)問(wèn)題。like “%aaa%” 不會(huì)使用索引知染,而like “aaa%”可以使用索引肋僧。

不要在列上進(jìn)行運(yùn)算

例如:select * from users where YEAR(adddate)<2007,將在每個(gè)行上進(jìn)行運(yùn)算持舆,這將導(dǎo)致索引失效而進(jìn)行全表掃描色瘩,因此我們可以改成:select * from users where adddate<’2007-01-01′

最后總結(jié)一下,MySQL只對(duì)以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些時(shí)候的like(不以通配符%或_開(kāi)頭的情形)逸寓。而理論上每張表里面最多可創(chuàng)建16個(gè)索引居兆,不過(guò)除非是數(shù)據(jù)量真的很多,否則過(guò)多的使用索引也不是那么好玩的竹伸。

建議:一個(gè)表的索引數(shù)最好不要超過(guò)6個(gè)泥栖,若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有必要。

5.1 索引分析

clip_image121.jpg
clip_image123.jpg

單表

建表SQL

案例

兩表

建表SQL

案例

三表

建表SQL

案例

clip_image125.jpg
clip_image127.jpg

5.2 索引失效(應(yīng)該避免)

建表SQL

案例(索引失效)

1.全值匹配我最愛(ài)

clip_image129.jpg

2.最佳左前綴法則

如果索引了多例勋篓,要遵守最左前綴法則吧享。指的是查詢從索引的最左前列開(kāi)始并且不跳過(guò)索引中的列。

clip_image131.jpg

3.不在索引列上做任何操作(計(jì)算譬嚣、函數(shù)钢颂、(自動(dòng)or手動(dòng))類型轉(zhuǎn)換),會(huì)導(dǎo)致索引失效而轉(zhuǎn)向全表掃描

clip_image133.jpg

4.存儲(chǔ)引擎不能使用索引中范圍條件右邊的列

clip_image135.jpg

5.盡量使用覆蓋索引(只訪問(wèn)索引的查詢(索引列和查詢列一致))拜银,減少select*

clip_image137.jpg
clip_image139.jpg

6.mysql在使用不等于(殊鞭!=或者<>)的時(shí)候無(wú)法使用索引會(huì)導(dǎo)致全表掃描

clip_image141.jpg

7.is null,is not null 也無(wú)法使用索引

clip_image143.jpg

8.like以通配符開(kāi)頭('$abc...')mysql索引失效會(huì)變成全表掃描操作

clip_image145.jpg

問(wèn)題:解決like'%字符串%'索引不被使用的方法遭垛??

1操灿、可以使用主鍵索引

2锯仪、使用覆蓋索引,查詢字段必須是建立覆蓋索引字段

3趾盐、當(dāng)覆蓋索引指向的字段是varchar(380)及380以上的字段時(shí)庶喜,覆蓋索引會(huì)失效!

9.字符串不加單引號(hào)索引失效

clip_image147.jpg

10.少用or,用它連接時(shí)會(huì)索引失效

clip_image149.jpg

11.小總結(jié)

假設(shè)index(a,b,c)

where語(yǔ)句 索引是否被使用
where a=3 Y,使用到a
where a=3 and b=5 Y,使用到a,b
where a=3 and b=5 and c=4 Y,使用到a,b,c
where b=3 或者 where b=3 and c=4 或者 where c=4 N
where a=3 and c=5 使用到a救鲤,但是c不可以
where a=3 and b>4 and c=5 使用到a和b
where a=3 and b like 'kk%' and c=4 Y,使用到a,b,c
where a=3 and b like '%kk' and c=4 Y,只用到a
where a=3 and b like '%kk%' and c=4 Y,只用到a
where a=3 and b like 'k%kk%' and c=4 Y,使用到a,b,c

like KK%相當(dāng)于=常量 %KK和%KK% 相當(dāng)于范圍

【優(yōu)化總結(jié)口訣】
會(huì)值匹配我最愛(ài)久窟,最左前綴要遵守;
帶頭大哥不能死蜒简,中間兄弟不能斷瘸羡;
索引列上少計(jì)算,范圍之后會(huì)失效搓茬;
LIKE百分寫(xiě)最右,覆蓋索引不寫(xiě)星队他;
不等空值還有or卷仑,索引失敗要少用;
VAR引號(hào)不可丟麸折,SQL高級(jí)也不難锡凝!

定值、范圍還是排序垢啼,一般order by是給個(gè)范圍

group by 基本上都需要進(jìn)行排序窜锯,會(huì)有臨時(shí)表產(chǎn)生

5.3 一般性建議

對(duì)于單鍵索引,盡量選擇針對(duì)當(dāng)前query過(guò)濾性更好的索引

在選擇組合索引的時(shí)候芭析,當(dāng)前Query中過(guò)濾性最好的字段在索引字段順序中锚扎,位置越靠前越好。

在選擇組合索引的時(shí)候馁启,盡量選擇可以能包含當(dāng)前query中的where子句中更多字段的索引

盡可能通過(guò)分析統(tǒng)計(jì)信息和調(diào)整query的寫(xiě)法來(lái)達(dá)到選擇合適索引的目的

避免全表掃描

對(duì)查詢進(jìn)行優(yōu)化驾孔,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引惯疙。

避免判斷null值

應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷翠勉,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:

select id from t where num is null

可以在num上設(shè)置默認(rèn)值0霉颠,確保表中num列沒(méi)有null值对碌,然后這樣查詢:

select id from t where num=0

避免不等值判斷

應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則引擎將放棄使用索引而進(jìn)行全表掃描蒿偎。

避免使用or邏輯

應(yīng)盡量避免在 where 子句中使用 or 來(lái)連接條件朽们,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描怀读,如:

select id from t where num=10 or num=20

可以這樣查詢:

select id from t where num=10

union all

select id from t where num=20

慎用in和not in邏輯

in 和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描华坦,如:

select id from t1 where num in(select id from t2 where id > 10)

此時(shí)外層查詢會(huì)全表掃描愿吹,不使用索引∠Ы悖可以修改為:

select id from t1,(select id from t1 where id > 10)t2 where t1.id = t2.id

此時(shí)索引被使用犁跪,可以明顯提升查詢效率。

注意模糊查詢

下面的查詢也將導(dǎo)致全表掃描:

select id from t where name like '%abc%'

模糊查詢?nèi)绻潜匾獥l件時(shí)歹袁,可以使用select id from t where name like 'abc%'來(lái)實(shí)現(xiàn)模糊查詢坷衍,此時(shí)索引將被使用。如果頭匹配是必要邏輯条舔,建議使用全文搜索引擎(Elastic search枫耳、Lucene、Solr等)孟抗。

避免查詢條件中字段計(jì)算

應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作迁杨,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:

select id from t where num/2=100

應(yīng)改為:

select id from t where num=100*2

避免查詢條件中對(duì)字段進(jìn)行函數(shù)操作

應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作凄硼,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描铅协。如:

select id from t where substring(name,1,3)='abc'--name以abc開(kāi)頭的id

應(yīng)改為:

select id from t where name like 'abc%'

WHERE子句“=”左邊注意點(diǎn)

不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算摊沉,否則系統(tǒng)將可能無(wú)法正確使用索引狐史。

組合索引使用

在使用索引字段作為條件時(shí),如果該索引是復(fù)合索引说墨,那么必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引骏全,否則該索引將不會(huì)被使用,并且應(yīng)盡可能的讓字段順序與索引順序相一致尼斧。

不要定義無(wú)異議的查詢

不要寫(xiě)一些沒(méi)有意義的查詢姜贡,如需要生成一個(gè)空表結(jié)構(gòu):

select col1,col2 into #t from t where 1=0

這類代碼不會(huì)返回任何結(jié)果集,但是會(huì)消耗系統(tǒng)資源的突颊,應(yīng)改成這樣:

create table #t(...)

exists

很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:

select num from a where num in(select num from b)

用下面的語(yǔ)句替換:

select num from a where exists(select 1 from b where num=a.num)

索引也可能失效

并不是所有索引對(duì)查詢都有效鲁豪,SQL是根據(jù)表中數(shù)據(jù)來(lái)進(jìn)行查詢優(yōu)化的,當(dāng)索引列有大量數(shù)據(jù)重復(fù)時(shí)律秃,SQL查詢可能不會(huì)去利用索引爬橡,如一表中有字段sex,male棒动、female幾乎各一半糙申,那么即使在sex上建了索引也對(duì)查詢效率起不了作用。

表格字段類型選擇

盡量使用數(shù)字型字段船惨,若只含數(shù)值信息的字段盡量不要設(shè)計(jì)為字符型柜裸,這會(huì)降低查詢和連接的性能缕陕,并會(huì)增加存儲(chǔ)開(kāi)銷。這是因?yàn)橐嬖谔幚聿樵兒瓦B接時(shí)會(huì)逐個(gè)比較字符串中每一個(gè)字符疙挺,而對(duì)于數(shù)字型而言只需要比較一次就夠了扛邑。

盡可能的使用 varchar 代替 char ,因?yàn)槭紫瓤勺冮L(zhǎng)度字段存儲(chǔ)空間小铐然,可以節(jié)省存儲(chǔ)空間蔬崩,其次對(duì)于查詢來(lái)說(shuō),在一個(gè)相對(duì)較小的字段內(nèi)搜索效率顯然要高些搀暑。

查詢語(yǔ)法中的字段

任何地方都不要使用 select * from t 沥阳,用具體的字段列表代替“*”,不要返回用不到的任何字段自点。

索引無(wú)關(guān)優(yōu)化

不使用*桐罕、盡量不使用union,union all等關(guān)鍵字桂敛、盡量不使用or關(guān)鍵字功炮、盡量使用等值判斷。

表連接建議不超過(guò)5個(gè)术唬。如果超過(guò)5個(gè)死宣,則考慮表格的設(shè)計(jì)。(互聯(lián)網(wǎng)應(yīng)用中)

表連接方式使用外聯(lián)優(yōu)于內(nèi)聯(lián)碴开。

外連接有基礎(chǔ)數(shù)據(jù)存在。如:A left join B,基礎(chǔ)數(shù)據(jù)是A博秫。

A inner join B潦牛,沒(méi)有基礎(chǔ)數(shù)據(jù)的,先使用笛卡爾積完成全連接挡育,在根據(jù)連接條件得到內(nèi)連接結(jié)果集巴碗。

大數(shù)據(jù)量級(jí)的表格做分頁(yè)查詢時(shí),如果頁(yè)碼數(shù)量過(guò)大即寒,則使用子查詢配合完成分頁(yè)邏輯橡淆。

Select * from table limit 1000000, 10

Select * from table where id in (select pk from table limit 100000, 10)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市母赵,隨后出現(xiàn)的幾起案子逸爵,更是在濱河造成了極大的恐慌,老刑警劉巖凹嘲,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件师倔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡周蹭,警方通過(guò)查閱死者的電腦和手機(jī)趋艘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)疲恢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瓷胧,你說(shuō)我怎么就攤上這事显拳。” “怎么了搓萧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵杂数,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我矛绘,道長(zhǎng)耍休,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任货矮,我火速辦了婚禮羊精,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘囚玫。我一直安慰自己喧锦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布抓督。 她就那樣靜靜地躺著燃少,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铃在。 梳的紋絲不亂的頭發(fā)上阵具,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音定铜,去河邊找鬼阳液。 笑死,一個(gè)胖子當(dāng)著我的面吹牛揣炕,可吹牛的內(nèi)容都是我干的帘皿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼畸陡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鹰溜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起丁恭,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤曹动,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后涩惑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體仁期,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了跛蛋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熬的。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赊级,靈堂內(nèi)的尸體忽然破棺而出押框,到底是詐尸還是另有隱情,我是刑警寧澤理逊,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布橡伞,位于F島的核電站,受9級(jí)特大地震影響晋被,放射性物質(zhì)發(fā)生泄漏兑徘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一羡洛、第九天 我趴在偏房一處隱蔽的房頂上張望挂脑。 院中可真熱鬧,春花似錦欲侮、人聲如沸崭闲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刁俭。三九已至,卻和暖如春韧涨,著一層夾襖步出監(jiān)牢的瞬間牍戚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工虑粥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翘魄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓舀奶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親斋射。 傳聞我的和親對(duì)象是個(gè)殘疾皇子育勺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353