你知道哪些情況不適合創(chuàng)建索引嗎
1. 在where中使用不到的字段,不要設(shè)置索引
WHERE條件(包括GROUP BY贴膘、ORDER BY))里用不到的字段不需要創(chuàng)建索引,索引的價值是快速定位拔恰,如果起不到定位的字段通常是不需要創(chuàng)建索引的话侄。舉個例子:
SELECT course_id, student_id, create_time
FROM student_info
WHERE student_id = 41251 ;
因為我們是按照student_id 來進行檢索的,所以不需要對其他字段創(chuàng)建索引敛瓷,即使這些字段出現(xiàn)在SELECT字段中叁巨。
2. 數(shù)據(jù)量小的表最好不要使用索引
如果表記錄太少,比如少于1000個呐籽,那么是不需要創(chuàng)建索引的锋勺。表記錄太少,是否創(chuàng)建索引 對查詢效率的影響并不大 狡蝶。甚至說庶橱,查詢花費的時間可能比遍歷索引的時間還要短,索引可能不會產(chǎn)生優(yōu)化效果贪惹。
舉例:創(chuàng)建表1:
CREATE TABLE t_without_index(
a INT PRIMARY KEY AUTO_INCREMENT,
b INT
);
提供存儲過程1:
#創(chuàng)建存儲過程
DELIMITER //
CREATE PROCEDURE t_wout_insert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 900
DO
INSERT INTO t_without_index(b) SELECT RAND()*10000;
SET i = i + 1;
END WHILE;
COMMIT;
END //
DELIMITER ;
#調(diào)用
CALL t_wout_insert();
創(chuàng)建表2:
CREATE TABLE t_with_index(
a INT PRIMARY KEY AUTO_INCREMENT,
b INT,
INDEX idx_b(b)
);
創(chuàng)建存儲過程2:
#創(chuàng)建存儲過程
DELIMITER //
CREATE PROCEDURE t_with_insert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 900
DO
INSERT INTO t_with_index(b) SELECT RAND()*10000;
SET i = i + 1;
END WHILE;
COMMIT;
END //
DELIMITER ;
#調(diào)用
CALL t_with_insert();
查詢對比:
mysql> select * from t_without_index where b = 9879;
+------+------+
| a | b |
+------+------+
| 1242 | 9879 |
+------+------+
1 row in set (0.00 sec)
mysql> select * from t_with_index where b = 9879;
+-----+------+
| a | b |
+-----+------+
| 112 | 9879 |
+-----+------+
1 row in set (0.00 sec)
你能看到運行結(jié)果相同苏章,但是在數(shù)據(jù)量不大的情況下,索引就發(fā)揮不出作用了。
結(jié)論:在數(shù)據(jù)表中的數(shù)據(jù)行數(shù)比較少的情況下枫绅,比如不到 1000 行泉孩,是不需要創(chuàng)建索引的。
3. 有大量重復(fù)數(shù)據(jù)的列上不要建立索引
在條件表達式中經(jīng)常用到的不同值較多的列上建立索引并淋,但字段中如果有大量重復(fù)數(shù)據(jù)寓搬,也不用創(chuàng)建索引。比如在學(xué)生表的“性別""字段上只有“男"與“"女"兩個不同值县耽,因此無須建立索引句喷。如果建立索引,不但不會提高查詢效率酬诀,反而會 嚴重降低數(shù)據(jù)更新速度脏嚷。
舉例1:要在 100 萬行數(shù)據(jù)中查找其中的 50 萬行(比如性別為男的數(shù)據(jù)),一旦創(chuàng)建了索引瞒御,你需要先訪問 50 萬次索引父叙,然后再訪問 50 萬次數(shù)據(jù)表,這樣加起來的開銷比不使用索引可能還要大肴裙。
舉例2:假設(shè)有一個學(xué)生表趾唱,學(xué)生總數(shù)為 100 萬人,男性只有 10 個人蜻懦,也就是占總?cè)丝诘?10 萬分之 1甜癞。學(xué)生表 student_gender 結(jié)構(gòu)如下。其中數(shù)據(jù)表中的 student_gender 字段取值為 0 或 1宛乃,0 代表女性悠咱,1 代表男性。
CREATE TABLE student_gender(
student_id INT(11) NOT NULL,
student_name VARCHAR(50) NOT NULL,
student_gender TINYINT(1) NOT NULL,
PRIMARY KEY(student_id)
)ENGINE = INNODB;
如果我們要篩選出這個學(xué)生表中的男性征炼,可以使用:
SELECT * FROM student_gender WHERE student_gender = 1
運行結(jié)果(10 條數(shù)據(jù)析既,運行時間 0.696s
)
你能看到在未創(chuàng)建索引的情況下,運行的效率并不高谆奥。如果針對student_gender字段創(chuàng)建索引呢?
SELECT * FROMstudent-gender WHERE student-gender = 1
同樣是10條數(shù)據(jù)眼坏,運行結(jié)果相同,時間卻縮短到了0.052s
酸些,六幅提升了查詢的效率宰译。
你能看到在未創(chuàng)建索引的情況下,運行的效率并不高魄懂。如果針對student_gender字段創(chuàng)建索引呢?
SELECT * FROMstudent-gender WHERE student-gender = 1
同樣是10條數(shù)據(jù)沿侈,運行結(jié)果相同,時間卻縮短到了 0.052s
市栗,大幅提升了查詢的效率肋坚。
其實通過這兩個實驗?zāi)阋材芸闯鰜恚饕膬r值是幫你快速定位。如果想要定位的數(shù)據(jù)有很多智厌,那么索引就失去了它的使用價值诲泌,比如通常情況下的性別字段。
結(jié)論:當數(shù)據(jù)重復(fù)度大铣鹏,比如 高于 10% 的時候敷扫,也不需要對這個字段使用索引。
4. 避免對經(jīng)常更新的表創(chuàng)建過多的索引
第一層含義︰頻繁更新的字段不一定要創(chuàng)建索引诚卸。因為更新數(shù)據(jù)的時候葵第,也需要更新索引,如果索引太多合溺,在更新索引的時候也會造成負擔卒密,從而影響效率。
第二層含義:避免對經(jīng)常更新的表創(chuàng)建過多的索引棠赛,并且索引中的列盡可能少哮奇。此時,雖然提高了查詢速度睛约,同時卻會降低更新表的速度鼎俘。
5. 不建議用無序的值作為索引
例如身份證、UUID(在索引比較時需要轉(zhuǎn)為ASCII辩涝,并且插入時可能造成頁分裂)贸伐、MD5、HASH怔揩、無序長字符串等捉邢。
6. 刪除不再使用或者很少使用的索引
表中的數(shù)據(jù)被大量更新,或者數(shù)據(jù)的使用方式被改變后商膊,原有的一些索引可能不再需要伏伐。數(shù)據(jù)庫管理員應(yīng)當定期找出這些索引,將它們刪除翘狱,從而減少索引對更新操作的影響秘案。
7. 不要定義冗余或重復(fù)的索引
① 冗余索引
舉例:建表語句如下
CREATE TABLE person_info(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
birthday DATE NOT NULL,
phone_number CHAR(11) NOT NULL,
country varchar(100) NOT NULL,
PRIMARY KEY (id),
KEY idx_name_birthday_phone_number (name(10), birthday, phone_number),
KEY idx_name (name(10))
);
我們知道砰苍,通過 idx_name_birthday_phone_number 索引就可以對 name 列進行快速搜索潦匈,再創(chuàng)建一個專門針對 name 列的索引就算是一個 冗余索引 ,維護這個索引只會增加維護的成本赚导,并不會對搜索有什么好處茬缩。
② 重復(fù)索引
另一種情況,我們可能會對某個列 重復(fù)建立索引 吼旧,比方說這樣:
CREATE TABLE repeat_index_demo (
col1 INT PRIMARY KEY,
col2 INT,
UNIQUE uk_idx_c1 (col1),
INDEX idx_c1 (col1)
);
我們看到凰锡,col1 既是主鍵、又給它定義為一個唯一索引,還給它定義了一個普通索引掂为,可是主鍵本身就會生成聚簇索引裕膀,所以定義的唯一索引和普通索引是重復(fù)的,這種情況要避免勇哗。