MySQL组合索引和最左匹配原则

什么时候创建组合索引?

当我们的where查询存在多个条件查询的时候,我们需要对查询的列创建组合索引

为什么不对没一列创建索引

  • 减少开销
  • 覆盖索引
  • 效率高

减少开销:假如对col1、col2、col3创建组合索引,相当于创建了(col1)、(col1,col2)、(col1,col2,col3)3个索引

覆盖索引:假如查询SELECT col1, col2, col3 FROM 表名,由于查询的字段存在索引页中,那么可以从索引中直接获取,而不需要回表查询

效率高:对col1、col2、col3三列分别创建索引,MySQL只会选择辨识度高的一列作为索引。假设有100w的数据,一个索引筛选出10%的数据,那么可以筛选出10w的数据;对于组合索引而言,可以筛选出100w*10%*10%*10%=1000条数据

最左匹配原则

假设我们创建(col1,col2,col3)这样的一个组合索引,那么相当于对col1列进行排序,也就是我们创建组合索引,以最左边的为准,只要查询条件中带有最左边的列,那么查询就会使用到索引

创建测试表

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(10) NOT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_id_name_age` (`id`,`name`,`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
复制代码

填充100w测试数据

DROP PROCEDURE pro10;
CREATE PROCEDURE pro10()
BEGIN
	DECLARE i INT;
	DECLARE char_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
	DECLARE return_str varchar(255) DEFAULT '';
	DECLARE age INT;
	SET i = 1;
	WHILE i < 5000000 do
		SET return_str = substring(char_str, FLOOR(1 + RAND()*62), 8);
		SET i = i+1;
		SET age = FLOOR(RAND() * 100);
		INSERT INTO student(id, name, age) values(i, return_str, age);
	END WHILE;
END;

CALL pro10();
复制代码

场景测试

EXPLAIN SELECT * FROM student WHERE id = 2;
复制代码

可以看到该查询使用到了索引

EXPLAIN SELECT * FROM student WHERE id = 2 AND name = 'defghijk';
复制代码

可以看到该查询使用到了索引

EXPLAIN SELECT * FROM student WHERE id = 2 AND name = 'defghijk' and age = 8;
复制代码

可以看到该查询使用到了索引

EXPLAIN SELECT * FROM student WHERE id = 2 AND age = 8;
复制代码

可以看到该查询使用到了索引

EXPLAIN SELECT * FROM student WHERE name = 'defghijk' AND age = 8;
复制代码

可以看到该查询没有使用到索引,类型为index,查询行数为4989449,几乎进行了全表扫描,由于组合索引只针对最左边的列进行了排序,对于name、age只能进行全部扫描

EXPLAIN SELECT * FROM student WHERE name = 'defghijk' AND id = 2;

EXPLAIN SELECT * FROM student WHERE age = 8 AND id = 2;

EXPLAIN SELECT * FROM student WHERE  name = 'defghijk' and age = 8 AND id = 2;
复制代码

可以看到如上查询也使用到了索引,id放前面和放后面查询到的结果是一样的,MySQL会找出执行效率最高的一种查询方式,就是先根据id进行查询

总结

如上测试,可以看到只要查询条件的列中包含组合索引最左边的那一列,不管该列在查询条件中的位置,都会使用索引进行查询。

欢迎各路英雄好汉指正文中的错误!

转载于:https://juejin.im/post/5c862b3ff265da2dda698456

### MySQL索引前缀匹配原理 在MySQL中,当创建复合索引(也称为联合索引),例如 `(a, b, c)` 时,查询优化器利用这些列的方式依赖于所谓的“前缀”原则。这意味着如果有一个由多个字段组成的索引,则只有从边开始连续的部分可以被用于加速检索操作[^1]。 具体来说,在执行查询语句期间: - 如果仅涉及第一个字段 `a` 的条件过滤,那么整个多列索引都能发挥作用; - 当同时存在针对 `a` `b` 字段的约束时,同样能够充分利用此组合键来提高效率; - 对于包含所有三个字段 (`a`, `b`, `c`) 的筛选表达式而言,自然也能享受到佳性能增益; 然而需要注意的是,一旦中间某个位置上的属性缺失了相应的限定条件——比如只提供了关于 `b` 或者 `c` 的值而忽略了前面更靠的位置上定义好的那些项——则后续右边剩余部分便不再适用于当前这条记录集的选择过程之中。 因此为了确保数据库引擎尽可能高效地运用已建立起来的各种形式的数据结构来进行快速定位目标数据行的操作,设计表结构以及编写SQL语句的时候应当充分考虑到这一点,并据此合理规划各个业务逻辑所对应的访问路径。 ```sql -- 正确使用前缀的例子 SELECT * FROM table_name WHERE a = 'value' AND b = 'value'; -- 错误使用前缀的例子 SELECT * FROM table_name WHERE b = 'value'; ``` #### 使用场景 对于需要频繁按照某些特定模式进行范围扫描或者精确查找的应用场合特别适合采用基于前缀特性的索引来提升整体读取效能。这包括但不限于以下几种情况: - 经常依据某几个固定顺序排列的关键字做为输入参数参与联接运算或是子查询内部作为参照对象的情况。 - 需要支持复杂条件下带有多种不同维度限制因子的同时作用下的统计分析需求。 - 场景涉及到大量时间序列型资料处理任务时,通过构建适当的时间戳与其他辅助信息相结合形成的有序列表可以帮助加快历史版本回溯等功能实现的速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值