专栏首页喵叔's 专栏从大厂不允许使用 SELECT * 说开去

从大厂不允许使用 SELECT * 说开去

作为开发人员数据库查询语句我们经常用到,但是你是否想过为什么大厂都会强制开发人员禁止使用 SELECT * 语句?你一定会说因为效率低啊,多差除了一些无用的数据。如果是这么想的,那就继续听我来说。

零、探究原因

1. 表象层面

我们先来看一下使用 SELECT * 会产生什么样的后果。首先它会增加查询分析器的解析成本,数据库不仅仅会解析字段内容,还会解析对象、权限、属性等更多的相关内容,这些多余的东西往往会给数据库带来很大的负担。其次如果数据库进行了字段的删除/增加就会造成与 resultMap 不一致进而导致程序报错无法正确运行。接着在查询数据量很大的情况下还会增加网络开销和数据传输时长,这时如果表中存在日志内容字段或者二进制字段的情况下,数据传输的量将以几何倍数增长,不管数据库和应用程序是否位于同一台服务器(或集群),都会感觉到明显的卡顿,而且数据表中一般会包含 varchar 、blob 和 text 这样的大文本/超大文本类型的字段,这样就更近一步的增加了 IO 开销。在 MySQL 的数据库引擎是 InnoDB 的情况下,遇到这种大文本/超大文本类型字段的情况会将超过 728 字节的数据序列化到另一个地方存储,每次读取相对应的记录的时候就会增加一次操作步骤。

2. 索引层面

上面所说的只是从表象层面来说的,这些我们都能看得到感受得到。下面我们从 MySQL 的索引层面来说一下。使用 SELECT * 会造成 MySQL 优化器的 覆盖索引 策略失效,这个策略在业内又是被公认为速度和效率都是极好的,那么这样一来这个优秀的策略就无用武之地了。那么为什么说覆盖索引策略是极好的呢,下面我们通过一个例子来讲解一下。

2.1 单例索引

我们的数据库中存在一张表 emp,表中包含 id,name,sex,birthday 字段,其中 id 是主键,sex 存在索引。这时磁盘上就存在两个 B+ 树,一棵是主键索引树(聚集索引)保整行内容,另一棵是 sex 索引树(辅助索引)保存 id 和 sex内容。当我们通过希望 where 语句查询出 sex 等于男的数据时,那么where 条件可以通过 sex 索引过滤掉不符合要求的数据,如果用户只想获取 sex 和 id 字段的数据的话,sex 索引就可以直接返回所需的数据,这种情况时极好的。如果我们的查询语句是 SELECT * 的话,那么 MySQL 通过 sex 索引树过滤出数据后,还要再去主键索引树上去拿到符合条件的所有字段的内容,这样就多了一次索引树的查询,进而降低了查询速度。在这里需要注意的是:我们在开发中辅助索引的数量往往大于聚集索引的数量,那么利用辅助索引去进行查询的时候是从内存中直接读取数据的,聚集索引有时会去读取磁盘这样就出现了拆查询缓慢的问题。

2.2 联合索引

前面我们提到了辅助索引,辅助索引一般包含单列索引和联合索引。单列索引就是我们前面所讲的 sex 索引,下面我们重点讲解一下联合索引。所谓的联合索引就是多个字段联合在一起,这是我们所知道的。但是大部分开发人员所不知道的是联合多因其实是建立了多个索引,比如我们将上例中的 name、sex、birthday 三个字段做一个联合索引,那么在数据库中实际上是创建了三个索引,分别是:name 索引,sex_name 索引、sex_name_birthday 索引 (注意:这里只是为了看起来易读,实际数据库索引命名不是这样的)。

讲到这里我问各位读者一个小问题:where name='xxx' and birthday ='2019-01-01'这个语句使用了上面三个索引中的哪些?肯定会有读者说用到了 name 索引和sex_name_birthday 索引,真的是这样吗?我们不妨先来看看 MySQL 中索引的使用规则,我们可以把索引看成一本词典,name、sex、birthday 分别是这本辞海的字母、字和词,如果我们想要查询字(sex)的时候就需要知道这个字的以什么字母(name)开头,如果我们要查询词(birthday )的时候就需要知道这个此是以什么字(sex)开头,这个开头的字(sex)是以什么字母(name) 开头的。这么一说你应该就明白了吧,前面所问的那个问题的答案就是只用到了 name 索引,这是因为 birthday 位于 sex_name_birthday 索引 我们无法跨过 sex_name 索引去查询它,就像我们无法通过字母去查询某个词一样。

讲了这么多我们来总结一下使用联合索引的好处。首先它可以减少开销,当我们建立了一个联合索引就相当于创建了多个索引,我们知道多创建一个索引就会增加磁盘和操作开销,但是使用联合索引则会减少这些开销。其次可以实现索引覆盖,MySQL 可以通过遍历索引直接获取到数据,进而减少了回表的操作和 IO 操作。最后通过联合索引可以在筛选出符合条件的数据的同时提高查询效率。

2.3 建立索引的注意事项

当然并不是说任何情况下都适合建立索引,下面列出了不适合建立索引的情况。

  • 表数据量很小的情况,建立索引会引起开销增大;
  • 不经常使用的列,在这样的列上建立索引完全没有用;
  • 数据频繁更新的列,建立索引会影响新增和更新的效率;
  • 数据平均分布的列。

一、总结

这篇文章从 SELECT * 讲起,最后以联合索引结尾,内容稍显复杂但是只要记住:避免使用 SELECT * ,会使覆盖索引策略失效,多索引情况下尽量使用联合索引减少开销。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Entity Framework 小知识(四)

    在EF中并没有提供包含索引和过滤索引的创建方法,那么我们就么发创建了吗?答案是否定的,我们可以通过迁移类进行创建包含索引和过滤索引。 首先我们通过 Add-M...

    喵叔
  • Entity Framework 索引

    Entity Framwework 6 设置和使用索引,是一个比较 egg 疼的事情,为什么这么说呢?因为Entity Framwework 6的不同版本有不同...

    喵叔
  • 准备工作与简介

    C# 可以说是当今所有开发语言中最好的开发语言,微软会每隔一段时间就推出一个新的 .NET Framework 框架,随着每次新框架的推出 C# 语言也会增加新...

    喵叔
  • 如何优化mysql的范围查询

    本文预计分为两个部分: (1)联合索引部分的基础知识 在这个部分,我们温习一下联合索引的基础 (2)联合索引部分的实战题 在这个部分,列举几个我认为算是实战中的...

    sunsky
  • 聚集索引VS非聚集索引

    悟空聊架构
  • 聚集索引VS非聚集索引

    悟空聊架构
  • 12.3 索引文件

    1、除了文件本身(称做数据区)之外,另建立一张指示逻辑记录和物理记录之间一一对应关系的表——索引表。

    C语言入门到精通
  • MySQL 字符集、校对规则及索引

    字符集指的是一种从二进制编码到某类字符符号的映射。校对规则则是指某种字符集下的排序规则。

    happyJared
  • 12.3 索引文件

    1、除了文件本身(称做数据区)之外,另建立一张指示逻辑记录和物理记录之间一一对应关系的表——索引表。

    C语言入门到精通
  • MySQL 索引的原理与应用:索引类型,存储结构与锁

    在数据结构与算法--索引 https://url.wx-coder.cn/O07eI 一节中,我们讨论了 B+Tree, LSM-Tree 这样的文件索引以及全...

    王下邀月熊

扫码关注云+社区

领取腾讯云代金券