MySQL适合创建索引的11种情况及不适合创建索引的7种情况

数据准备:

  • 创建学生表和课程表
#创建学生表
CREATE TABLE `student_info`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`student_id` INT NOT NULL,
`name` VARCHAR(20) DEFAULT NULL,
`course_id` INT NOT NULL,
`class_id` INT(11) DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY(`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

#创建课程表
CREATE TABLE `course`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`course_id` INT NOT NULL,
`course_name` VARCHAR(40) DEFAULT NULL,
PRIMARY KEY(`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  • 创建俩函数生成随机数和随机字符串
# 创建随机产生字符串函数
DELIMITER //
CREATE FUNCTION RAND_STRING(n INT)
RETURNS VARCHAR(255)
BEGIN
        DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
		DECLARE ret_str VARCHAR(255) DEFAULT '';
		DECLARE i INT DEFAULT 0;
		while i < n DO
				SET ret_str = CONCAT(ret_str,SUBSTRING(chars_str, FLOOR(1 + RAND() * 52), 1));
				SET i = i + 1;
		END WHILE;
		RETURN ret_str;
END //

# 创建随机数函数
DELIMITER //
CREATE FUNCTION rand_num (from_num INT, to_num INT)
RETURNS INT(11)
BEGIN
		DECLARE i INT DEFAULT 0;
		SET i = FLOOR(from_num + RAND() * (to_num - from_num + 1));
		RETURN i;

END //
DELIMETER;
  • 创建随机过程模拟插入数据
#创建插入课程表存储过程
DELIMITER //
CREATE PROCEDURE insert_course(max_num INT)
BEGIN
		DECLARE i INT DEFAULT 0;
		SET autocommit = 0;
		REPEAT
				SET i = i + 1;
				INSERT INTO cours(course_id, course_name)
				VALUES (rand_num(10000, 10100), rand_string(6));
				UNTIL i = max_num
		END REPEAT;
		COMMIT;
END //
DELIMITER;

# 创建插入学生信息存储过程
DELIMITER //
CREATE PROCEDURE insert_stu(max_num INT)
BEGIN
		DECLARE i INT DEFAULT 0;
		SET autocommit = 0;
		REPEAT
				SET i = i + 1;
				INSERT INTO student_info(course_id, class_id, student_id, name)
				VALUES(rand_num(10000, 10100), rand_num(10000, 10200), rand_num(1, 200000), rand_string(6));
				UNTIL i = max_num
		END REPEAT;
		COMMIT;
END//
DELIMITER;
  • 调用存储过程
# 调用存储过程
CALL insert_course(100);
CALL insert_stu(1000000);

哪些情况适合创建索引

  • 字段的数值有唯一性的限制

具有唯一索引的字段,即使是组合字段,也必须建成唯一索引。唯一索引对 insert 的速度损耗可以忽略,但是提高的查找速度是明显的。

  • 频繁作为 where 查询条件的字段

在 student_id 字段上没有索引时查询:耗时235ms

 添加索引:

CREATE INDEX idx_sid ON student_info(student_id);

此时再次查询:,耗时23ms,时间相差十倍左右!所以当某字段经常做 where的查询条件,一定要为其添加索引。

以下每个情况代码验证和以上一样,分别运行有相应索引和没有索引两种情况,比较运行时间。明显可以看出索引可以大大的降低查询时间。一一列举代码略显冗余,所以这里不再赘述代码,只列出剩余的情况及相关说明。

  •  经常GROUP BY 或 ORDER BY的列

排序后分组或排序自然是非常快了!

  • UPDATE、DELETE 的 WHERE 条件列
  • DISTINCT  字段需要创建索引

排序后去重自然也更快了!

  • 多表 JOIN 连接操作时,创建索引注意事项

首先,连接表的数量尽量不要超过三张,因为每增加一张表就相当于增加了一次嵌套的循环。数量级增长会非常快,严重影响查询的效率。

其次,对 WHERE 条件创建索引, 因为 WHERE 才是对数据过滤的条件。如果数据量非常大的情况下,没有 WHERE 条件过滤是非常可怕的。

最后,对用于连接的字段创建索引,并且该字段在多张表中的类型必须一致。比如 course_id 在两张表中都为 int(11) 类型,而不能一个为 int 另一个为varchar 类型。

  • 使用列的类型小的创建索引
  • 使用字符串前缀创建索引

在 VARCHAR 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。

  • 区分度高(散列度高)的列适合作为索引
  • 使用越频繁的列要放到联合索引的越左侧
  • 在多个字段都要创建索引的情况下,联合索引优于单值索引

限制索引的数目

在实际工作中,我们也需要注意平衡。索引的数目不是越多越好。我们需要限制每张表上的索引数量,建议单张表索引数量不超过6个,原因如下:

  1. 每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。
  2. 索引会印象 INSERT, DELETE, UPDATE 等语句的性能,因为表中数据更改的同时,索引也会调整和更新,造成负担。
  3. 优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估。以生成出一个最好的计划。如果同时有多个索引都可以用于查询时,会增加Mysql优化器生成执行计划时间,降低查询性能。

哪些情况不适合创建索引

  • 在 WHERE 中使用不到的字段,不要设置索引

同理,如GROUP BY 或 ORDER BY 条件里用不到的字段,也不要设置索引。原因也很简单,不需要快速定位,设置索引也没有用!

  • 数据量小的表最好不要使用索引

在数据量很小的时候,原本查询时间已经很短了,不必要再添加索引。索引的回表等操作可能会使耗费时间更多!

  • 有大量重复数据的列上不要建立索引
  • 避免对经常需要更新的表创建过多的索引
  • 不建议用无序的值作为索引
  • 删除不再使用或很少使用的索引
  • 不要定义冗余或者重复的索引

小结

索引是一把双刃剑,可提高查询效率,但也会降低插入和更新的速度并占用磁盘空间。选择索引的最终目的是为了使查询的速度更快,上面给出的原则是最基本的原则。也要结合实际情况来决定是否使用索引!

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值