一、小明接到一个需求,让统计一下订单表当月的卖票数和总金额

小明分析发现,订单表是业务重心,数据量会很大,目前已经有六十多万的数据,应该给时间字段建立索引。

订单金额字段加索引 订单总金额_字段


订单金额字段加索引 订单总金额_sql_02

数据库里的库、表、字段强烈建议都使用小写,用下划线代替驼峰命名。这个是公司传统艺能。

于是小明开始编写sql语句,遵从最左前缀原则,时间字段不加函数,防止索引失效,查1月份的数据

订单金额字段加索引 订单总金额_sql_03

  • 看一下查询时间

订单金额字段加索引 订单总金额_字段_04


果然啪的一下,很快啊!

然后小明想,怎么知道我用了索引呢?于是搜到了得用explain执行计划来分析。

订单金额字段加索引 订单总金额_索引_05


果然,type为range,说明对时间字段使用了范围索引,key_len为63,代表使用到的索引长度;rows是扫描行数。

小明很满意。


二、又接到一个需求,让统计一下年度的订单销售量和总金额

小明如法炮制,sql语句改一下时间范围

订单金额字段加索引 订单总金额_字段_06


再看一下查询时间

订单金额字段加索引 订单总金额_sql_07


怎么会需要9秒钟这么长?不是有索引吗?

订单金额字段加索引 订单总金额_字段_08


一看执行计划,哎?type为ALL,全表扫描了?

当使用MySql 非主键索引进行查询时 如果扫描数据量接近全表数据量时,mysql会进行全表扫描不会使用索引(主键索引除外),这也是为什么不建议在区分度低的字段上建索引,也会导致全表扫描。

rows不能直接理解为扫描行数, 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数也就是mysql认为必须要逐行去检查和判断的记录的条数,实际是mysql根据估算的所需读取的行数决定是全表扫描还是使用索引。

小明苦思冥想,给数量字段和金额字段都建立索引?都没效果。

这时小明看了亿点点MySQL索引底层的数据结构,分析出来,应该是发生回表了。

顺便猜测了日期字段的索引结构,画了个图

订单金额字段加索引 订单总金额_订单金额字段加索引_09


发现索引结构中没有factNum,factTotal这两个字段,只有主键id;那岂不是查出年度的记录后,里面每一行的记录再根据id回到主聚集索引中找到这两个值?

哦~于是小明想到建立组合索引,组合索引怎么建?遵循范围条件放最后!

  • 建组合索引
  • 订单金额字段加索引 订单总金额_字段_10

  • 再执行一下统计语句
  • 订单金额字段加索引 订单总金额_订单金额字段加索引_11

  • 看查询时间
  • 订单金额字段加索引 订单总金额_mysql_12

  • 看执行计划
  • 订单金额字段加索引 订单总金额_字段_13

  • 果然,变得快多了!虽然还是需要半秒钟~

所以

组合索引的结构中,对索引字段从左进行了排序,所以不需要再回表查询factNum,factTotal字段。结构就不画了,主要是从左到右进行索引排序。

测试过日期字段放前面,比放后面慢0.2s左右,所以还是要遵循组合索引中,范围条件放最后这个规约。

结尾

这是近来看视频学到的,为了记忆深刻,实践了一下。
这里用的是陈年旧表,数据库服务器性能不算高,表的索引字段也很多。但是了解数据结构,遵从索引规约后,相对来说提升是很明显的。但索引不是越多越好,要有目标的建立索引。
实践型分享,有错误的地方一起改正。