MySQL是一款常用的關(guān)系型數(shù)據(jù)庫管理系統(tǒng),在日常開發(fā)中我們經(jīng)常會用到索引優(yōu)化查詢,其中單列索引是最常用的一種索引類型。然而,當在一張表中存在多個單列索引時,這些索引之間是如何相互影響的呢?本文將從多個角度探討這個問題。
首先,我們先來看一下多個單列索引在取出數(shù)據(jù)時的命中情況。以以下表為例:
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `age` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `name_index` (`name`), KEY `age_index` (`age`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
可以看到,該表中除了主鍵索引外,還有名為name_index和age_index的兩個單列索引。
當我們執(zhí)行以下查詢語句時:
SELECT * FROM users WHERE name='John' AND age=25;
此時,MySQL優(yōu)化器會根據(jù)表中的索引信息選擇最優(yōu)的索引進行查詢。如果同時有多個單列索引可以利用,MySQL會選擇其中最嚴格(過濾出最少行數(shù))的一個索引。
在本例中,name和age字段都有單列索引,然而name字段比age字段更加嚴格,因為它是字符串類型,索引命中的幾率相對較小,同時記錄數(shù)又較多,因此MySQL會選擇使用name_index索引,再根據(jù)age=25的條件進行過濾,最終得出結(jié)果。
那么,如果我們在查詢語句中只使用其中一個索引呢?例如:
SELECT * FROM users WHERE age=25;
此時MySQL會直接使用age_index索引,不會考慮name_index索引的使用,因為該索引無法加速查詢過程,只會增加查詢時間和負擔。
除了命中情況,多個單列索引還可能存在“覆蓋索引”的問題。覆蓋索引是指查詢結(jié)果只需要訪問到索引的數(shù)據(jù)頁即可,無需再去訪問數(shù)據(jù)頁的行記錄,這樣可以提高查詢性能。
以以下查詢?yōu)槔?/p>
SELECT name, age FROM users WHERE name='John';
此時,name_index索引能夠命中,但不是覆蓋索引,還需要再去訪問數(shù)據(jù)頁獲取age字段的值。如果我們添加一個聯(lián)合索引:
CREATE INDEX `name_age_index` ON `users` (`name`, `age`);
再執(zhí)行同樣的查詢語句時:
SELECT name, age FROM users WHERE name='John';
此時MySQL會優(yōu)先使用name_age_index聯(lián)合索引,因為該索引可以覆蓋查詢結(jié)果,只需訪問索引頁即可,無需再去訪問數(shù)據(jù)頁。這樣可以加快查詢速度,并降低對磁盤的I/O操作。
綜上所述,當一張表中存在多個單列索引時,MySQL會根據(jù)索引的嚴格程度和能否覆蓋查詢結(jié)果等因素選擇最優(yōu)的索引進行查詢,同時還需要注意聯(lián)合索引的使用,以減少I/O操作,加速查詢效率。