共计 3863 个字符,预计需要花费 10 分钟才能阅读完成。
这篇文章主要讲解了“怎么合理的使用 MySQL 索引结构和查询”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着丸趣 TV 小编的思路慢慢深入,一起来研究和学习“怎么合理的使用 MySQL 索引结构和查询”吧!
一、高性能索引 1、查询性能问题
在 MySQL 使用的过程中,所谓的性能问题,在大部分的场景下都是指查询的性能,导致查询缓慢的根本原因是数据量的不断变大,解决查询性能的最常见手段是:针对查询的业务场景,设计合理的索引结构。
2、索引使用原则
索引的使用并不是越多越好,而是针对业务下的查询场景,不断的改进和优化,例如电商系统中用户订单的场景,假设存在如下表结构:
CREATE TABLE `ds_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 主键 id ,
`user_name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT= 用户表
CREATE TABLE `ds_order` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 主键 id ,
`user_id` int(11) NOT NULL COMMENT 用户 ID ,
`order_no` varchar(60) NOT NULL COMMENT 订单号 ,
`product_name` varchar(50) DEFAULT NULL COMMENT 产品名称 ,
`number` int(11) DEFAULT 1 COMMENT 个数 ,
`unit_price` decimal(10,2) DEFAULT 0.00 COMMENT 单价 ,
`total_price` decimal(10,2) DEFAULT 0.00 COMMENT 总价 ,
`order_state` int(2) DEFAULT 1 COMMENT 1 待支付,2 已支付,3 已发货,4 已签收 ,
`order_remark` varchar(50) DEFAULT NULL COMMENT 订单备注 ,
`create_time` datetime DEFAULT NULL COMMENT 创建时间 ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT= 订单表
用户和订单的管理表,在电商的业务中很常见,可以通过对该业务分析,看看常用的索引结构:
用户方:
基于用户的查询,多数是基于用户 ID(user_id);
基于订单号(order_no),查看物流的信息;
运营方:
基于时间段的流水明细 (create_time) 或排序;
基于订单状态的筛选 (order_state) 和统计;
基于产品 (product_name) 的数据统计分析;
这样一个流程分析走下来,即可以在开发初期,确定哪些结构是查询必须用到的,预先做好索引结构,避免数据量庞大到影响性能时再去考虑使用索引。
有些时候会考虑放弃一些查询条件,例如基于产品名称的数据统计,走定时任务的方式,用来缓解表的查询压力,处理的方式是多样的。
优秀的索引设计,都是建立在对业务数据的理解上,考虑业务数据的查询方式,提高查询效率。
二、索引创建 1、单列索引
单列索引,即索引建立在表的一个字段上,一个表可以有多个单列索引,使用起来相对比较简单:
CREATE INDEX user_id_index ON ds_order(user_id) USING BTREE;
主键索引,或者上述的 user_id_index 都是单列索引。
业务场景:基于用户自己对订单查询,和管理系统,订单和用户的关联查询,所以订单表的 user_id 需要一个索引。
2、组合索引
组合索引包含两个或两个以上的列,组合索引相比单列索引复杂很多,如何建立组合索引,和业务关联度非常高,在使用组合索引时,还需要考虑查询条件的顺序。
CREATE INDEX state_create_time_index ON `ds_order`(`create_time`,`order_state`);
如上就是组合索引,实际包含的是 2 个索引 (create_time) (create_time,order_state),这样查询就涉及到最左前缀的原则,必须按照顺序来查询,这里下面详说。
业务场景:首先单说这里组合索引,在业务开发中,常见订单状态的统计,基于统计结果做运营分析,另外就是在运营系统中,基于创建时间段的筛选条件是默认存在的,避免全部数据实时扫描;一些其他的常见查询也都是条件加时间段的查询模式。
3、前缀索引
如果需要加索引的列是很长的字符串,那么索引会变的庞大臃肿,起到的效果可能并不是很明显。这时候可以截取列的前面一部分,创建索引,节省空间,这样可能会出现索引的选择性下降,即基于前缀索引查询出的相似数据可能很多:
ALTER TABLE ds_order ADD KEY (order_no(30)) ;
这里由于订单号太长,所以选择前面 30 位作为前缀索引,用作订单号的查询,当然这里涉及到一个非常经典的业务场景,订单号机制。
业务场景:前缀索引一个典型的应用场景就是处理订单号,一个看似很长的订单号,其实包含的信息非常多:
时间点:就是订单生成的时间,年月日时分秒;
标识位:即一个唯一的 UID,保证订全单号唯一;
埋点一:在很多业务中,在订单号记录产品类目;
埋点二:通常会标识产品属性,例如颜色,口味等;
错位符:防止订单号被分析,会随机一段错位符号;
如此一段分析下来,实际订单号是非常长的,所以需要引入前缀索引机制,前缀索引期望使用的索引长度可以筛选整个列的基数,例如上面的订单号:
大部分业务基于时间节点筛选足够,即索引长度 14 位;
如果是并发业务,很多时间节点相同,则索引长度是时间点 + 标识位;
注意:如果业务允许的情况下,一般要求前缀索引的长度有唯一性,例如上面的时间和标示位。
4、其他索引
例如全文索引等,这些用到的场景不多,如果数据庞大,又需要检索等,通常会选择强大的搜索中间件来处理。显式唯一索引,这种也会在程序上做规避,避免不友好的异常被抛出。
三、索引查询
如何创建最优的索引,是一件不容易的事情,同样在查询的时候,是否使用索引也是一件难度极大的事情,经验之谈:多数是性能问题暴露的时候,才会回头审视查询的 SQL 语句,针对性能问题,做相应的查询优化。
1、单列查询
这里直接查询主键索引,MySQL 的主键一般选择自增,所以速度非常快。
EXPLAIN SELECT * FROM ds_order WHERE id=2;
EXPLAIN SELECT * FROM ds_order WHERE id=1+1;
EXPLAIN SELECT * FROM ds_order WHERE id+1=1;
这里,id=2,id=1+1,MySQL 都可以自动解析,但是 id+ 1 是在索引列上执行运算,直接导致主键索引失效。这里有一个基本策略,如果非要在单列索引上做操作,可以将该逻辑放在程序中,到 MySQL 层面,SQL 语句越干净利落越好。
2、前缀索引查询
前缀索引的查询,可以基于 Like 对特定长度筛选,或者全订单号查询。
EXPLAIN SELECT * FROM ds_order WHERE order_no LIKE 202008011314158723628732871625%
EXPLAIN SELECT * FROM ds_order WHERE order_no= 20200801131415872362873287162572367
3、组合索引查询
查询最麻烦的就是组合索引,或者说查询条件组合起来,都使用了索引:
EXPLAIN SELECT * FROM ds_order
WHERE create_time 2020-08-01 00:00:00 AND order_state= 1
上述基于组合索引中列的顺序,使用了组合索引:state_create_time_index。
EXPLAIN SELECT * FROM ds_order WHERE create_time 2020-08-01 00:00:00
上述只使用 create_time 列,也同样使用了索引结构。
EXPLAIN SELECT * FROM ds_order WHERE order_state= 1
上述如果只使用 order_state 条件,则结果显示全表扫描。
EXPLAIN SELECT * FROM ds_order
WHERE create_time 2020-08-01 00:00:00 AND order_no LIKE 20200801%
上述则基于组合索引的 create_time 列和单列索引 order_no 保证查询条件都使用了索引。
通过上面几个查询案例,索引组合索引使用的注意事项如下:
组合索引必须按索引最左列开始查询;
不能跳过组合字段查询, 这样无法使用索引。
感谢各位的阅读,以上就是“怎么合理的使用 MySQL 索引结构和查询”的内容了,经过本文的学习后,相信大家对怎么合理的使用 MySQL 索引结构和查询这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是丸趣 TV,丸趣 TV 小编将为大家推送更多相关知识点的文章,欢迎关注!