一個(gè)不留神,索引就創(chuàng)建重復(fù)了
相信沒(méi)有人會(huì)故意創(chuàng)建重復(fù)的冗余的索引,很多重復(fù)和冗余的索引都是在不經(jīng)意間創(chuàng)建的,今天松哥來(lái)和大家捋一捋這個(gè)問(wèn)題。
因?yàn)槲覀內(nèi)粘T谑褂?MySQL 的過(guò)程中,基本上都是使用 InnoDB 引擎,所以接下來(lái)的討論主要是基于 InnoDB 引擎的 B+Tree 索引來(lái)討論,其他的哈希索引全文索引等不在討論范圍種。
1. 與聯(lián)合索引重復(fù)
在前面的文章中,松哥通過(guò)好幾篇文章和大家分享了聯(lián)合索引,包括它涉及到的覆蓋索引、前綴匹配等等,聯(lián)合索引好用,但是對(duì)聯(lián)合索引理解不到位的話,可能會(huì)創(chuàng)建出如下的重復(fù)索引:
CREATE TABLE `user2` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`address` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(16) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_index1` (`username`,`address`),
KEY `user_index2` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
可以看到,這里創(chuàng)建了兩個(gè)索引:
- user_index1:這個(gè)索引包含兩個(gè)字段,username 在前 address 在后。
- user_index2:這個(gè)索引包含一個(gè)字段 username。
(username,address) 索引既可以當(dāng)成聯(lián)合索引來(lái)用,也可以通過(guò)最左匹配原則當(dāng)成單獨(dú)的 (username) 索引來(lái)用。
所以,如果再為 username 字段單獨(dú)創(chuàng)建一個(gè)索引就沒(méi)有必要了,這反而會(huì)導(dǎo)致增刪改的時(shí)候速度變慢。
不過(guò)怎么說(shuō)呢,上面這個(gè)結(jié)論適用于 99% 的場(chǎng)景,可能會(huì)有一些特殊情況,例如想把 (username) 和某一個(gè)特別長(zhǎng)的字段建立一個(gè)聯(lián)合索引,此時(shí)如果單獨(dú)使用 username 字段進(jìn)行搜索的話,效率可能降低,此時(shí)視搜索的重要程度,看是否需要?jiǎng)?chuàng)建一個(gè)重復(fù)的索引。
2. 主鍵加入聯(lián)合索引中
來(lái)看看下面這個(gè)索引:
CREATE TABLE `user2` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`address` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(16) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_index` (`username`,`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
一個(gè)名為 user_index 的索引中包含了兩個(gè)字段 username 和 id,其中 id 是主鍵。
在??什么是 MySQL 的“回表”???一文中,松哥和大家聊了,索引按照物理存儲(chǔ)方式可以分為聚簇索引和非聚簇索引。
我們?nèi)粘Kf(shuō)的主鍵索引,其實(shí)就是聚簇索引(Clustered Index);主鍵索引之外,其他的都稱之為非主鍵索引,非主鍵索引也被稱為二級(jí)索引(Secondary Index),或者叫作輔助索引。
對(duì)于主鍵索引和非主鍵索引,使用的數(shù)據(jù)結(jié)構(gòu)都是 B+Tree,唯一的區(qū)別在于葉子結(jié)點(diǎn)中存儲(chǔ)的內(nèi)容不同:
- 主鍵索引的葉子結(jié)點(diǎn)存儲(chǔ)的是一行完整的數(shù)據(jù)。
- 非主鍵索引的葉子結(jié)點(diǎn)存儲(chǔ)的則是主鍵值以及索引列的值。
這是兩者最大的區(qū)別。
既然主鍵已經(jīng)存在于葉子結(jié)點(diǎn)中,那當(dāng)然沒(méi)有在聯(lián)合索引中加入主鍵了。
好啦,幾個(gè)小小的注意點(diǎn),希望能給小伙伴們啟發(fā)。
參考資料:
《高性能 MySQL》