最近写作生涯遭逢了滑铁卢,写了两篇文章浏览量都不怎么样,但还是要持续分享所学,服务端的菜鸡不能输,要从新称霸中原,233333当然这是很难的,后端优良作者切实太多了,还得持续加油。回归主题,最近又在重新学习MySQL,想起了阿里开发手册禁用select * 查问语句,这是为什么呢

引言

阿里巴巴开发手册中指出:

【强制】在表查问中,一律不要应用 * 作为查问的字段列表,须要哪些字段必须明确写明

阐明:

  • 减少查问分析器解析老本
  • 增减字段容易与 resultMap 配置不统一
  • 无用字段减少网络 耗费,尤其是 text 类型的字段

文章将从这几个方面开展阐明

减少查问分析器解析老本

首先介绍一下MySQL根本架构,根本构造如下图:

MySQL 根本架构能够分为 Server 层和存储引擎层两局部。Server 层包含连接器、查问缓存、分析器、优化器、执行器等。存储引擎层负责数据的存储和提取,其架构模式是插件式的,反对 InnoDB、MyISAM、Memory 等多个存储引擎

当咱们执行一条查问语句:select * from t where id = 1,在MySQL中执行过程如下:

  • 在真正执行select * from t where id = 1时首先须要输出命令mysql -uroot -p,通过连接器将客户端和服务层建设起连贯
  • 建设起连贯当前输出select * from t where id = 1这条SQL
  • 首先查找查问缓存中是否曾经执行过该条语句
  • 若未命中查问缓存,则执行select * from t where id = 1这条SQL,分析器会对这条SQL进行词法剖析。
  • MySQL 从输出的select这个关键字辨认进去这是一个查问语句。
  • 把字符串t辨认成表名t,把字符串id辨认成列id
  • 判断输出的这个 SQL 语句是否满足 MySQL 语法

如果应用select 来查问语句,分析器须要进行额定的解析,如果间接指定成列名,则不须要进行额定的解析,间接辨认成列名

失去MySQL优化器“笼罩索引”策略优化的可能性

假如有一条sql语句为select * from t where name = "何甜甜",其中id为主键,name为索引,而实际上这么写的目标只是想查问指定name的id

在innodb存储引擎中,索引能够分为非主键索引和主键索引,主键索引和主键的区别在于叶子节点存放数据的不同。主键索引中叶子节点寄存的是整行数据,而非主键索引中叶子节点寄存的是主键的值。当初咱们来看select * from t where name = "何甜甜"这条语句是如何执行的

因为name是索引且name是查问条件,查问优化器会抉择应用name索引。首先依据name查问到该name对应的主键id为1,因为须要查问的是指定name的所有数据,因而还须要依据主键id进行一次回表操作。所谓回表操作是指非主键索引中查问到主键id,在依据主键id到主键索引中查问到所有数据,具体过程可看下图

后面曾经提到查问到的中只是用到了id字段,如果将原来的sql语句批改为select id from t where name = "何甜甜",就能够防止一次回表操作。在非主键索引中曾经笼罩了查问需要【即所需查问的ID已在非主键索引上了】,也被称为笼罩索引。通过笼罩索引能够缩小回表次数,从而显著晋升查问性能,因而在理论写sql过程中应该尽量避免写select 这样的查问语句,写之前先反诘是否真的须要用到这么多字段

减少IO操作

BLOB和TEXT是为了存储很大的数据而设计的字符串数据类型,当BLOB和TEXT值太大时,InnoDB会应用专门的内部存储区域来进行存储,每个值在行内须要1~4字节存储一个指针,而后在内部存储区域存储理论的值,如果查问的中有BLOB或TEXT类型的字段,则查问的BLOB或TEXT列须要在进行额定一次IO操作去内部存储区域将数据查问到,所以尽量避免应用select

减少数据传输工夫和网络开销

传输数据过多会减少网络开销。同时,查问语句执行时会先将查问到的数据放到查问缓存区中,再从查问缓存中将后果返回给客户端,如果查问到的数据量十分大则须要花很多工夫来存储后果,所以在说一次,防止应用select *