索引 1.什么是索引
數(shù)據(jù)庫除了數(shù)據(jù)外,還維護(hù)者滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式指向數(shù)據(jù),也就是一種快速查找數(shù)據(jù)庫中內(nèi)容的工具,目的是為了提高查找的效率
2.索引分類
單值索引、唯一索引、復(fù)合索引
3.索引失效
1)like以通配符開頭(‘%abc’)會導(dǎo)致索引失效,違反最左前綴法則
2)在索引列上做任何操作(計算、函數(shù)、類型轉(zhuǎn)換),會導(dǎo)致索引失效而轉(zhuǎn)向全表掃描
3)存儲引擎不能使用索引中范圍條件右邊的列,舉例: id,name from where id > 50 and name = ‘張三’,會導(dǎo)致name索引失效
4)盡量使用覆蓋索引,不要 *
5)MySQL在使用不等于(!=或)的時候無法使用索引會導(dǎo)致全表掃描,理由也很簡單,B+Tree葉子節(jié)點用指針相連且是排好序的,這種數(shù)據(jù)結(jié)構(gòu)只能解決有序的定值查詢,像不等于這種無法利用索引查詢。
6)IS NULL、IS NOT NULL無法使用索引,理由同上
7)字符串不加單引號索引失效
? 隱式轉(zhuǎn)換–>函數(shù)操作
8)用or連接時會導(dǎo)致索引失效
最左前綴法則:
在創(chuàng)建了多列索引的情況下,查詢從索引的最左前列開始且不能跳過索引中的列。最佳左前綴法則就是說如果創(chuàng)建了多個索引,在使用索引時要按照創(chuàng)建索引的順序來使用,不能缺少或跳過,當(dāng)然如果只使用最左邊的索引列,也就是第一個索引是可以的。
為什么要遵循最左前綴法則:
聯(lián)合索引一個節(jié)點上有兩個鍵值對
a是有序排序的,b是在a字段有序的前提下在a的后邊有序排列的(相對有序),加入不遵循最佳做前綴法則,就是沒有a直接去查找b,而沒有a的b是沒有順序的
為什么在使用不等式的時候會失效,是因為當(dāng)你確定的是a的范圍的時候,a的范圍雖然確定了但b的順序是無序的,所以你無法在B+樹上用二分查找查找到該精確值
like后邊的百分號如果放到兩邊或者左邊都是不走索引的 放到右邊的話某些情況下會走索引 因為字母在排序的時候是先按照第一個字母去作比較,然后按照第二個去比 字符串的尾部是沒有順序的like失效的原理就是和最佳做前綴類似
對于優(yōu)化器來說,如果等號兩邊的數(shù)據(jù)類型不一致,則會發(fā)生隱式轉(zhuǎn)換。
例如, * from where phone = ;這條SQL語句就會變?yōu)? * from where cast(phone as int) = ;
由于對索引列進(jìn)行了函數(shù)操作,從而導(dǎo)致索引失效。
SQL優(yōu)化的三個點:
sql的語句執(zhí)行順序
FROM
# 選取表,將多個表數(shù)據(jù)通過笛卡爾積變成一個表。
ON
# 對笛卡爾積的虛表進(jìn)行篩選
JOIN
# 指定join,用于添加數(shù)據(jù)到on之后的虛表中,例如left join會將左表的剩余數(shù)據(jù)添加到虛表中
WHERE
# 對上述虛表進(jìn)行篩選
GROUP BY
# 分組
# 用于子句進(jìn)行判斷,在書寫上這類聚合函數(shù)是寫在判斷里面的
# 對分組后的結(jié)果進(jìn)行聚合篩選
# 返回的單列必須在group by子句中,聚合函數(shù)除外
# 數(shù)據(jù)除重
ORDER BY
# 排序
LIMIT
SQL優(yōu)化策略
1. 盡量避免在字段開頭模糊查詢,會導(dǎo)致數(shù)據(jù)庫引擎放棄索引進(jìn)行全表掃描
2.盡量避免使用in 和not in,會導(dǎo)致引擎走全表掃描。
3. 盡量避免使用 or,會導(dǎo)致數(shù)據(jù)庫引擎放棄索引進(jìn)行全表掃描
4. 盡量避免進(jìn)行null值的判斷,會導(dǎo)致數(shù)據(jù)庫引擎放棄索引進(jìn)行全表掃描
5.盡量避免在where條件中等號的左側(cè)進(jìn)行表達(dá)式、函數(shù)操作,會導(dǎo)致數(shù)據(jù)庫引擎放棄索引進(jìn)行全表掃描。
6. 當(dāng)數(shù)據(jù)量大時海量數(shù)據(jù)快速查詢算法,避免使用where 1=1的條件。通常為了方便拼裝查詢條件,我們會默認(rèn)使用該條件,數(shù)據(jù)庫引擎會放棄索引進(jìn)行全表掃描。
7. 查詢條件不能用 或者 !=
8. where條件僅包含復(fù)合索引非前置列
9. 隱式類型轉(zhuǎn)換造成不使用索引
10. order by 條件要與where中條件一致,否則order by不會利用索引進(jìn)行排序
11. 正確使用hint優(yōu)化語句
11. 正確使用hint優(yōu)化語句
語句其他優(yōu)化
1. 避免出現(xiàn) *
首先, * 操作在任何類型數(shù)據(jù)庫中都不是一個好的SQL編寫習(xí)慣。
使用 * 取出全部列,會讓優(yōu)化器無法完成索引覆蓋掃描這類優(yōu)化,會影響優(yōu)化器對執(zhí)行計劃的選擇,也會增加網(wǎng)絡(luò)帶寬消耗,更會帶來額外的I/O,內(nèi)存和CPU消耗。
建議提出業(yè)務(wù)實際需要的列數(shù),將指定列名以取代 *。2. 避免出現(xiàn)不確定結(jié)果的函數(shù)
特定針對主從復(fù)制這類業(yè)務(wù)場景。由于原理上從庫復(fù)制的是主庫執(zhí)行的語句,使用如now()、rand()、()、()等不確定結(jié)果的函數(shù)很容易導(dǎo)致主庫與從庫相應(yīng)的數(shù)據(jù)不一致。另外不確定值的函數(shù),產(chǎn)生的SQL語句無法利用query cache。
3.多表關(guān)聯(lián)查詢時,小表在前,大表在后。
在MySQL中,執(zhí)行 from 后的表關(guān)聯(lián)查詢是從左往右執(zhí)行的(相反),第一張表會涉及到全表掃描,所以將小表放在前面,先掃小表,掃描快效率較高,在掃描后面的大表,或許只掃描大表的前100行就符合返回條件并了。
例如:表1有50條數(shù)據(jù),表2有30億條數(shù)據(jù);如果全表掃描表2,你品,那就先去吃個飯再說吧是吧。
4. 使用表的別名
當(dāng)在SQL語句中連接多個表時,請使用表的別名并把別名前綴于每個列名上。這樣就可以減少解析的時間并減少哪些友列名歧義引起的語法錯誤。
5. 用where字句替換字句
避免使用字句,因為只會在檢索出所有記錄之后才對結(jié)果集進(jìn)行過濾,而where則是在聚合前刷選記錄,如果能通過where字句限制記錄的數(shù)目,那就能減少這方面的開銷。中的條件一般用于聚合函數(shù)的過濾海量數(shù)據(jù)快速查詢算法,除此之外,應(yīng)該將條件寫在where字句中。
where和的區(qū)別:where后面不能使用組函數(shù)
6.調(diào)整Where字句中的連接順序
前刷選記錄,如果能通過where字句限制記錄的數(shù)目,那就能減少這方面的開銷。中的條件一般用于聚合函數(shù)的過濾,除此之外,應(yīng)該將條件寫在where字句中。
where和的區(qū)別:where后面不能使用組函數(shù)
6.調(diào)整Where字句中的連接順序
MySQL采用從左往右,自上而下的順序解析where子句。根據(jù)這個原理,應(yīng)將過濾數(shù)據(jù)多的條件往前放,最快速度縮小結(jié)果集。