自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊索引失效的經(jīng)典場(chǎng)景

數(shù)據(jù)庫(kù) MySQL
因?yàn)樵谟卸鄠€(gè)索引的情況下,MySQL優(yōu)化器一般會(huì)通過(guò)比較掃描行數(shù)、是否需要臨時(shí)表以及是否需要排序等,來(lái)作為選擇索引的判斷依據(jù)。

前置條件

數(shù)據(jù)庫(kù)版本為5.7.17。

創(chuàng)建一張user表,預(yù)置500w條數(shù)據(jù),每個(gè)字段的值都是前綴加上從0開(kāi)始計(jì)數(shù)的數(shù)字,累加到5000000,如圖:

然后用explain來(lái)解析一下有沒(méi)有走索引。

最左匹配原則

我們首先建一個(gè)組合索引,username,jobno,company三個(gè)字段:

首先執(zhí)行以下幾個(gè)sql:

EXPLAIN SELECT * FROM `user` WHERE username = 'cxj1000000' AND jobno = 'jn1000000' AND company = 'com1000000';
EXPLAIN SELECT * FROM `user` WHERE username = 'cxj1000000';
EXPLAIN SELECT * FROM `user` WHERE username = 'cxj1000000' AND jobno = 'jn1000000';
EXPLAIN SELECT * FROM `user` WHERE jobno = 'jn1000000' AND username = 'cxj1000000';
EXPLAIN SELECT * FROM `user` WHERE username = 'cxj1000000' AND company = 'com1000000';

發(fā)現(xiàn)都走了索引。

接下來(lái)再執(zhí)行幾個(gè)sql:

EXPLAIN SELECT * FROM `user` WHERE jobno = 'jn1000000' AND company = 'com1000000';
EXPLAIN SELECT * FROM `user` WHERE company = 'com1000000';
EXPLAIN SELECT * FROM `user` WHERE jobno = 'jn1000000' ;

發(fā)現(xiàn)沒(méi)有走索引。

結(jié)論:最左匹配原則要求查詢(xún)的sql語(yǔ)句中,必須包含最左邊的字段,在username,jobno,company的組合索引中,username是最左邊的字段,那么查詢(xún)的sql語(yǔ)句中的where條件中,必須包含username字段,而與sql語(yǔ)句中username的使用順序無(wú)關(guān)。

索引列上有計(jì)算

根據(jù)主鍵ID查詢(xún),毫無(wú)疑問(wèn)會(huì)走主鍵索引,但如果像下面這種:

EXPLAIN SELECT * FROM `user` WHERE id + 1 = 2

可以看到?jīng)]有走索引。

總結(jié):如果索引列參與了計(jì)算,不會(huì)命中索引。像這種情況可以變換一下等式,把運(yùn)算放到等號(hào)右邊,就會(huì)命中索引。

EXPLAIN SELECT * FROM `user` WHERE id = 2 - 1

查詢(xún)條件帶or

上面所說(shuō)的最左匹配原則中,只要查詢(xún)語(yǔ)句中包含username就會(huì)走索引,但如果我們把a(bǔ)nd條件換成or,即:

SELECT * FROM `user` WHERE username = 'cxj13' OR jobno = 'jn13'

可以看到并沒(méi)有走索引,而是全表掃描,所以在帶有or的查詢(xún)語(yǔ)句中,索引將失效,除非所有條件都帶有索引。也就是說(shuō),username有索引,jobno也必須要建一個(gè)索引才會(huì)生效。

like查詢(xún)

在username字段上新建索引user_idx_normal_username,不使用%模糊查詢(xún):

SELECT * FROM `user` WHERE username LIKE 'cxj'

使用前置%:

使用后置%:

前后都用%:

結(jié)論:模糊查詢(xún)中,只要使用了%都不會(huì)走索引,不使用%號(hào)時(shí)可以走索引。

字段類(lèi)型不同

還是使用username進(jìn)行查詢(xún),username的字段類(lèi)型是字符串類(lèi)型,我們知道以下語(yǔ)句:

SELECT * FROM `user` WHERE username = 'cxj13'

肯定是會(huì)走索引的,但如果我們不用引號(hào)引用起來(lái),而是:

SELECT * FROM `user` WHERE username = 100

會(huì)發(fā)現(xiàn)沒(méi)有走索引:

結(jié)論:字符串的索引字段在查詢(xún)時(shí)數(shù)據(jù)需要用引號(hào)引用,否則索引失效。

查詢(xún)語(yǔ)句包含in

這種就比較特殊了,走不走索引不是絕對(duì)的,跟所查詢(xún)的數(shù)據(jù)量跟總表數(shù)據(jù)量的比例有關(guān)。

我們新建一張表:

CREATE TABLE `test` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`dept` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8

然后往這張表里插入10條數(shù)據(jù):

首先執(zhí)行以下語(yǔ)句:

SELECT * FROM test WHERE id IN (1)

執(zhí)行結(jié)果:

可以看到走了索引,需要注意的是type,我們知道type表示所走索引的一個(gè)效率值,它的結(jié)果的好壞依次為:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL。

一般來(lái)說(shuō),至少要達(dá)到range級(jí)別,當(dāng)type=index或者ALL時(shí),表示效率低下,需要優(yōu)化。我們看到只查詢(xún)一條記錄時(shí),不但走了索引,而且type=const,效率較高。我們擴(kuò)大下范圍:

SELECT * FROM test WHERE id IN (1,2,3)

從執(zhí)行結(jié)果上看,也走了索引,但此時(shí)type=range,效率降低了。再擴(kuò)大下范圍:

SELECT * FROM test WHERE id IN (1,2,3,4,5)

可以看到?jīng)]有走索引了,type=ALL,全表掃描。

結(jié)論:mysql優(yōu)化器會(huì)根據(jù)所查詢(xún)的數(shù)據(jù)量決定是走索引還是全表掃描。

mysql選錯(cuò)索引

我們?cè)俳ㄒ粋€(gè)demo表來(lái)說(shuō)明這種情況:

CREATE TABLE `demo` (
`id` int(11) NOT NULL,
`a` int(11) NOT NULL default 0,
`b` int(11) NOT NULL default 0,
PRIMARY KEY (`id`),
KEY `a` (`a`),
KEY `b` (`b`)
) ENGINE=InnoDB;

然后插入100w條數(shù)據(jù),執(zhí)行以下sql:

select * from demo where (a between 1000 and 2000) and (b between 50000 and 100000) limit 1

看一下執(zhí)行情況:

可以看到走了索引a,且只掃描了1001行,其實(shí)這正是我們需要的。

但如果我們加個(gè)排序,變成這樣:

SELECT * FROM demo WHERE (a BETWEEN 1000 AND 2000) AND (b BETWEEN 50000 AND 100000) ORDER BY b LIMIT 1

再看下執(zhí)行情況:

可以看到走了索引b,并且掃描了5w多行數(shù)據(jù),這樣效率顯然會(huì)降低,為什么會(huì)走索引b呢?

因?yàn)樵谟卸鄠€(gè)索引的情況下,mysql優(yōu)化器一般會(huì)通過(guò)比較掃描行數(shù)、是否需要臨時(shí)表以及是否需要排序等,來(lái)作為選擇索引的判斷依據(jù)。在這個(gè)例子中,優(yōu)化器看到根據(jù)b來(lái)進(jìn)行排序,認(rèn)為使用b效率更高,所以走了索引b。實(shí)際上,我們應(yīng)該使用a索引。

這種情況可以使用force index來(lái)強(qiáng)制使用索引a。

SELECT * FROM demo FORCE INDEX(a) WHERE (a BETWEEN 1000 AND 2000) AND (b BETWEEN 50000 AND 100000) ORDER BY b LIMIT 1;

可以看到,查詢(xún)走了索引a,并且只掃描了1001行。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2022-01-09 18:32:03

MySQL SQL 語(yǔ)句數(shù)據(jù)庫(kù)

2024-05-08 08:18:05

索引失效場(chǎng)景

2021-09-04 07:56:44

Spring事務(wù)失效

2024-04-19 13:57:30

索引數(shù)據(jù)庫(kù)查詢(xún)

2024-01-05 14:20:55

MySQL索引優(yōu)化器

2020-12-09 10:10:24

MySQL數(shù)據(jù)庫(kù)算法

2022-02-28 08:55:31

數(shù)據(jù)庫(kù)MySQL索引

2024-12-11 08:09:54

2024-05-07 08:23:03

Spring@Async配置

2022-02-14 16:53:57

Spring項(xiàng)目數(shù)據(jù)庫(kù)

2019-07-21 09:17:11

數(shù)據(jù)緩存架構(gòu)

2022-05-02 21:47:13

并發(fā)編程線程

2022-08-29 09:06:43

hippo4j動(dòng)態(tài)線程池

2020-12-08 09:45:07

MySQL數(shù)據(jù)庫(kù)索引

2023-09-28 09:07:54

注解失效場(chǎng)景

2020-05-21 11:29:58

復(fù)刻手機(jī)屏幕

2024-09-09 08:29:25

2024-01-29 08:28:01

Spring事務(wù)失效

2024-10-15 08:37:08

2015-05-20 13:48:26

MySQL索引
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)