索引设计的误区

单表索引数不超过5个

索引本质上就是一种数据结构,然而我们可以把索引映射到现实生活中,就好比是《深入浅出MySQL》这本书前面的目录。难不成我们说目录的章节不能超过5个吗?显然不可以的,在这么一个前提下,给一个索引增加一个上限值是不恰当的。所以涉及到慢查询的时候该加索引就加索引,不要给它们设置一个上限就好了。

但是我们也不能在设计索引的时候滥用索引,在数据库表增加太多无用的索引也是会带来一些副作用的,比如DML语句会变得很慢。

给高频字段加索引

这条在绝大部分情况下是对的,但是也不完全对。因为没有对应到场景上,所以不能说完全对,下面我们举例来说明一下。

假如你设计了一个APP用来发送消息的模块,由于发送的消息太多,表中已经有1亿的数据量。为了提高发送消息的速度,领导要求你开发一个功能,给发送消息未成功的用户再尝试发送一次消息。

这样我们就可以设计发送的状态status,这个status有三个值,0代表未发送,1代表已经发送,2代表发送失败。

相关的SQL语句如下:

select * from messages where status = 2;

正常情况下,大家都是发送成功的,发送失败的概率非常低。

然后我们从数据库表中做一个统计:

select status, count(*) from messages group by status;
| status | count(*) |
|      0 |     1000 |
|      1 | 99999000 |
|      2 |       24 |

这种情况称之为数据的倾斜度高。

在这种情况下,我们只需要查找status的值为2的情况即可,只要我们不统计status=1的情况,就不用在高频字段加上索引。所以在这个场景下,给高频字段加索引是不对的。

SQL执行顺序

我们已经知道了SQL的执行计划(explain),那么SQL的执行顺序呢?是不是跟Java代码一样,按照编码的顺序来执行的,让我们来看看吧。

在SQL语言中,执行顺序是按照一个固定的规则来执行的:

8、 SELECT
9、 DISTINCT <select_list>
1、 FROM <left_table>
3、 <join_type> JOIN <right_table>
2、 ON <join_condition>
4、 WHERE <where_condition>
5、 GROUP BY <group_by_list>
6、 WITH {CUBE|ROLLUP}
7、 HAVING <having_condition>
10、ORDER BY <order_by_condition>
11、LIMIT <limit_number>

从上面的规则得知,SQL执行顺序是11个步骤,最先执行的是FROM子句,最后执行的是LIMIT子句。

在SQL执行过程中,每一个步骤都会产生一个虚拟表(Virtual Table,简称VT),用来保存SQL的执行结果。下面分析一下SQL执行的整个过程:

  1. FROM。经过 FROM 语句得到一个虚拟表 VT1,如果有多表关联,会先执行笛卡尔积运算。
  2. ON。对虚拟表 VT1 执行 ON 条件筛选,筛选出符合 <join_condition> 条件的行,结果放入虚拟表 VT2 中。
  3. JOIN。如果是 OUTER JOIN 类型,上述表中未匹配到的行会作为外部行添加到虚拟表 VT2 中,生成虚拟表 VT3。
  4. WHERE。对虚拟表 VT3 应用 WHERE 条件,将符合 <where_condition> 条件的行插入到虚拟表 VT4 中。
  5. GROUP BY。根据 <group_by_list> 子句中的条件,对行记录进行分组处理,生成虚拟表 VT5。
  6. WITH。对表 VT5 进行 CUBE 或 ROLLUP 操作,生成虚拟表 VT6。
  7. HAVING。对虚拟表 VT6 的结果应用 HAVING 过滤,将符合 <having_condition> 条件的记录插入到虚拟表 VT7 中。
  8. SELECT。根据 SELECT 中的条件,选出指定的列,生成虚拟表 VT8。
  9. DISTINCT。对虚拟表 VT8 中的条件进行排重,产生虚拟表 VT9。
  10. ORDER BY。对虚拟表 VT9 中的记录,按照 <order_by_condition> 的条件进行排序操作,生成虚拟表 VT10。
  11. LIMIT。最后根据 LIMIT 的条件,取出指定的 LIMIT 区间的行,生成虚拟表 VT11,并将结果返回给用户。

因此,我们在进行SQL调优时,要按照SQL语句执行的顺序进行优化,重点处理执行成本比较高的部分:

  • 多表JOIN,先看JOIN的条件是否有索引,避免笛卡尔积的产生。
  • 检查WHERE条件的索引是否合理,尽可能缩小结果集的大小。
  • 检查GROUP BY条件上是否有索引,如果没有索引,MySQL会通过临时表来完成GROUP BY操作
  • 检查ORDER BY条件是否有索引,如果没有索引,MySQL会使用排序算法将结果集放入在临时表进行排序

查询优化器

现在的关系型数据库,基本都使用了基于成本的优化器。

现在估算成本的代价就是CPU代价+IO代价。在《数据库查询优化器的艺术》这本书讲到,MySQL数据库在有GROUP BY或者ORDER BY的操作下,没有索引的情况下会先走WHERE然后走GROUP BY和ORDER BY。反过来就是有索引的情况下,查询优化器会先走GROUP BY和ORDER BY再走WHERE。

因为数据库优化器会认为GROUP BY和ORDER BY不走索引的代价会大于WHERE不走索引的代价,所以在有索引的情况下,优化器会先优化给GROUP BY和ORDER BY走索引操作。

再深入的知识就要等自己去看书才能慢慢理解到了。

总结

  • 聊了网上的最佳实践有一些不完全对,并且举例说明了它们在某些情况下不正确的事实
  • SQL执行顺序还有索引优化部分
  • 查询优化器的代价

有帮到你的点赞、收藏一下吧

需要更多教程,微信扫码即可

MySQL索引(如何设计索引)相关推荐

  1. mysql 什么树_搞懂MySQL InnoDB B+树索引

    一.InnoDB索引 InnoDB支持以下几种索引: B+树索引 全文索引 哈希索引 本文将着重介绍B+树索引.其他两个全文索引和哈希索引只是做简单介绍一笔带过. 哈希索引是自适应的,也就是说这个不能 ...

  2. 【MySQL 优化】单一索引与复合索引

    MySQL 单一索引与复合索引 前 言 一.索引的最左前缀匹配原则 二.使用使用联合索引优势 1. 减少开销 2. 覆盖索引 3. 效率高 前 言 单一索引是指索引列为一列的情况,即新建索引的语句只实 ...

  3. 单一索引和复合索引区别及联系

    单一索引和复合索引区别及联系 - BABY的日志 - 网易博客  http://selectgoodboy.blog.163.com/blog/static/103212061201519111711 ...

  4. 单一索引和复合索引区别

    单一索引和复合索引区别及联系 - BABY的日志 - 网易博客  http://selectgoodboy.blog.163.com/blog/static/103212061201519111711 ...

  5. 面试mysql中怎么创建索引_阿里面试:MySQL如何设计索引更高效?

    有情怀,有干货,微信搜索[三太子敖丙]关注这个不一样的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系列文章. ...

  6. 13、MySQL索引的设计原则

    索引的设计可以遵循一些已有的原则,创建索引的时候应尽量考虑符合这些原则,便于提升索引的使用效率,更高效的使用索引.本节将介绍一些索引的设计原则. 1. 选择唯一性索引 唯一性索引的值是唯一的,可以更快 ...

  7. php 如何设计索引_Mysql学习浅谈mysql的索引设计原则以及常见索引的区别

    <Mysql学习浅谈mysql的索引设计原则以及常见索引的区别>要点: 本文介绍了Mysql学习浅谈mysql的索引设计原则以及常见索引的区别,希望对您有用.如果有疑问,可以联系我们. 索 ...

  8. mysql 二叉树表设计_mysql---B+tree索引的设计原理

    1.什么是数据库的索引 每种查找算法都只能应用于特定的数据结构之上,例如二分查找要求被检索数据有序,而二叉树查找只能应用于二叉查找树上,但是数据本身的组织结构不可能完全满足各种数据结构(例如,理论上不 ...

  9. Day4 MySql触发器视图索引以及设计优化

    触发器 MySQL包含对触发器的支持.触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将调用该对象,即表的操作事件触发表上的触发器的执行. 通过事件触发,不能传参 语法 CREA ...

最新文章

  1. F5与NetScaler比较
  2. C# 从DataSet导出到Excel
  3. php语言冒泡法,冒泡排序法(php)
  4. POJ 1286 Necklaces of Beads (Burnside定理,有限制型)
  5. P6772-[NOI2020]美食家【矩阵乘法,倍增】
  6. vue 子组件 调用、触发父组件中的方法
  7. [luogu3380][bzoj3196]【模板】二逼平衡树【树套树】
  8. Qt工作笔记-在ListWidget中单线程检索数据
  9. 01_13_JSP编译指令
  10. MFC中使用CTabCtrl或CPropertySheet实现标签页
  11. git常用命令及手动关联git本地和远端仓库
  12. excel计算式自动计算_全套Excel版工程自动计算表格+实用小工具,高效工作不加班...
  13. PRML 回归的线性模型
  14. 晨间日记模板 Web应用版 晨间日记软件 开源
  15. 常用颜色RGB表 色值
  16. windows图片和传真查看器
  17. 谷歌浏览器怎么更新升级 谷歌浏览器手动更新方法
  18. Spring Boot入门教程(四十):微信支付集成-刷卡支付
  19. 仿bilibili微信小程序2
  20. 运放-单电源运放和双电源运放

热门文章

  1. 神似华为Mate20!金立手机也开始复刻了...
  2. 频繁自燃 烧伤消费者!充电宝一哥召回部分产品
  3. ofo已还清蚂蚁金服欠款?回应:消息不实 但没有放弃
  4. 苹果发布会邀请函被玩坏:神似桂林西瓜霜
  5. MiniGUI编程--编辑框
  6. 基于Linux和MiniGUI的嵌入式系统软件开发指南(四)
  7. android 动态地改变某控件的大小
  8. python 调用外部程序 终端异常_python调用外部命令
  9. centos mysql php tomcat_CentOS yum安装Apache + PHP + Tomcat7 + MySQL
  10. 我的内核学习笔记5:proc目录文件创建及读写