您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

MySQL进阶篇 | 合理的使用索引结构和查询

时间:2020-08-03 10:26:34  来源:  作者:

一、高性能索引

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位作为前缀索引,用作订单号的查询,当然这里涉及到一个非常经典的业务场景,订单号机制。

业务场景:前缀索引一个典型的应用场景就是处理订单号,一个看似很长的订单号,其实包含的信息非常多:

MySQL进阶篇 | 合理的使用索引结构和查询

 

  • 时间点:就是订单生成的时间,年月日时分秒;
  • 标识位:即一个唯一的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保证查询条件都使用了索引。

通过上面几个查询案例,索引组合索引使用的注意事项如下:

  • 组合索引必须按索引最左列开始查询;
  • 不能跳过组合字段查询,这样无法使用索引;

四、索引其他说明

1、索引的优点

  • 基于注解或唯一索引保证数据库表中数据的唯一性;
  • 索引通过减少扫描表的行数提高查询的效率;

2、索引的缺点

  • 创建索引和维护索引,会耗费空间和实际;
  • 查询以外的操作增删改等,都需要动态维护索引;

3、索引使用总结

索引机制在MySQL中真的非常复杂,非专业的DBA(就是指开发人员),基本要熟练常见的索引结构,待过两年所谓的大厂,每个版本开发涉及的核心表SQL都是有专业DBA验收,复杂的查询都是提交需求,DBA直接输出查询SQL,当然在一般公司是没有DBA,需要开发在开发的过程中不断的思考,逐步优化,这需要对业务数据有一定的敏感度,对核心接口有执行监控,当发现稍微出现耗时情况,就可以不断优化,这个积累是个枯燥和进步的过程。

 



Tags:MySQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  Tags: MySQL  点击:(6)  评论:(0)  加入收藏
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  Tags: MySQL  点击:(10)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  Tags: MySQL  点击:(17)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  Tags: MySQL  点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  Tags: MySQL  点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  Tags: MySQL  点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  Tags: MySQL  点击:(16)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  Tags: MySQL  点击:(20)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  Tags: MySQL  点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Tags: MySQL  点击:(31)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(6)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(17)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(16)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(20)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(31)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(27)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条