写点什么

猴子都能懂的数据库避坑指南,还说你不会?,闭关在家 37 天“吃透”这份 345 页 PDF

用户头像
极客good
关注
发布于: 刚刚

MySQL 的开放性架构设计兼容了很多不种类的存储引擎(要是你足够厉害的话,也可以自己写一套存储引擎),存储引擎的设计初衷就是应对不同类型的数据仓库,工作中有见过不管什么表都直接用 Innodb(MySQL 5.0 的默认存储引擎,虽然大多数场景是不错的选择,但不是所有类型的表结构都适用)也见过根本不知道什么是存储引擎的同学,如果这些同学来设计数据库的话,那么你的系统就很容易踩到坑,出现很多你自己的预料不到的问题,合理的存储引擎的选择是应该结合实际业务场景,从目前最主流的 MySQL 来说,最常用的存储引擎主要是 MyISAM, Innodb,当然还有很多其他的存储引擎,例如 NDB(集群存储引擎),Memory(基于内存的存储引擎),Archive(归档存储引擎),因为这些平时使用不多,并不主流,工作中也很少用得到,意义不大,所以就不展开来讲,这里主要简单将下 MyISAM,Innodb 的区别,主要有以下特点:


MyISAM


  • 无事务机制,表级锁,自带计数功能(count 全表毫秒级响应)

  • 主要面向 OLAP 型应用,适合存储报表日志等类型数据


Innodb


  • 行级别,高并发,支持事务,四种事务隔离级别(MySQL 5.0+ 默认是读已提交)

  • 主要面向 OLTP 型应用,适合存储小量的事务型数据


字段类型的注意事项

因为不了解数据库的基本原理,所以很多初级程序员在选择数据库字段类型的时候比较迷茫,主要还是没有明确指导原则,工作中我见过在只有十几条数据的基础信息表中使用 long(8 字节)作为 id 主键类型,还有就像上面说的状态类型字段只有 0,1 值的字段使用 int (4 字节),还见过字符类型字段统一使用 varchar(255),数值类型字段统一使用 int,这种不基于数据库原理规则去随意选择字段的行为也只会出现在你 LocalHost 里的一些小项目或者玩具,基本上不了什么大台面


据我所知,主流的数据库大多都提供非常丰富的字段类型给开发者使用,老司机都是基于业务类型的判断从而选择合适的字段类型,最终收获的是性能(时间)和存储(空间)都非常低的高性能数据库,具体数据库有哪些字段类型,文章里面就不多数了,这方面的资料简直太多了,有兴趣的小伙伴可以自己去搜索,例如这里 [MySQL Data Types](


),那么对于新手而言如何选择字段类型呢?


简单的基本原则如下:(后面会具体将原因)


  1. 优先数字型字段(比如尽量使用 int 作为数据库主键 id 的类型而不是 varchar)

  2. 在满足需求的前提下,字段类型尽量足够的小(例如 age 字段应该考虑使用 tinyint 而不是 int 或者 long 类型)

  3. 时间字段考虑 timestamp (4 字节,支持 UTC)而不是 datetime(8 字节,不支持 UTC)


遵循基本规范能带来什么好处?


  1. 节省存储的开销,避免空间浪费(如果 1 条数据造成的空间开销 n,那么随着数据增长,浪费空间的比例也就是 n * n)

  2. 最好的性能(用户体验,另一种角度的节省资源-算力)


为什么要把“选择尽可能小的字段”作为基本原则?我们可以先看下 innodb 的逻辑存储结构



innodb 逻辑存储结构(图)


innodb 的存储结构如下:


  • 表空间(Tablespace)

  • 段(Segment):表空间由多个段组成

  • 区(Extent):单个区由 64 个连续页(Page)组成

  • 页(Page):磁盘的最小单位,默认大小 16 KB

  • 行(Row):每条记录,也称行数据,数据存储在页中 Page


上图可以看到读取最小单元 Page,匹配的数据都是从 Page 里面取出,按照这个简单的逻辑来说页中存储的行数据越多,数据库的性能就越高,怎么算出来的呢?按最小类型 2B 来计算 Row,那么 Page 的默认大小(16KB)是可以匹配到 7992 行记录,相反,如果你的 Row 行数据过大,假如一行 32 KB,那么数据库就需要 2 个连续的 Page 来保存你一行的数据,那么性能可想而知会有多低,前后性能差距差不多 1.6 万倍,这块也不深入讲了,有兴趣的小伙伴推荐去阅读经典书籍,这里的内容也只是书里的冰山一角

选择索引的注意事项

索引是一种用空间换时间的优化手段,是数据库最重要的优化手段,也是最后的杀手锏,索引


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


是否高效取决数据库设计是否良好,字段类型选择是否合理,索引是一把双刃剑,在提升检索速度的时候,也会减低插入,修改的性能(维护索引树的开销),在工作中这些年面试了不下几百人发现能把数据库索引原理讲明白的候选人非常的少,大多数情况下我们说索引通常默认指的是 BTREE 索引,BTREE 结构是特意为磁盘 I/O 这种缓慢的读取存储设计的数据结构,是一棵多路多叉树,和二叉树相反,每层的元素非常多,但是树的高度很矮(通常不会超过三层),从而可以保证最多不超过三次磁盘 I/O 即可定位到匹配的元素,所以说 BTREE 是一种非常适合磁盘的数据结构,也是 MySQL 默认索引类型是 BREE 的原因,如果能把这块吃透的话,那么去面试肯定是很大的加分项,索引在数据库可以简单参考下图:



简单说了下索引的结构,那么新手程序员在使用数据库所以的时候可以遵循以下原则:


  • 明白索引不是越多越好,过多的索引会降低读/写效率

  • 数据小和选择性低的列没有必要建索引(就像没必要为只有几页的书建目录)

  • 定期维护索引(移除不必要的索引,索引的最左匹配原则)

  • 谨慎使用全文索引,哈希索引,谨慎使用 FORCE INDEX 强制索引(强制会干扰优化器对索引选择的判断)


索引这块可以玩的还有很多,例如如何通过 SHOW INDEX 查看数据库为索引做出的评级(通过 Cardinality 统计),通过 Explain 查看 SQL 是否命中索引,rows 列可以看到 SQL 扫描的数据行数,Extra 列还可以查看索引匹配的类型,例如 Using index 代表完全匹配索引(无需回到 Primary Key 表查询数据,也称回表,甚至直接使用索引的排序,无需排序)往往说明性能不错,Using temporary 代表查询有使用临时表,一般出现于排序,多表 join 的情况,查询效率不高,建议优化

还有哪些要避开的坑?


人生总会遇到很多坑,与其自己去踩坑不如去总结别人踩过的坑,自己少走一些弯路也许可以更快的成功,这里是最后一章,不想把文章拉的太长,所以我在这里就直接抛出结论,不会再说明原因,如果对数据库有兴趣推荐看到最后我推荐的书籍


避免使用触发器/存储过程


  • 用存储过程写逻辑会导致代码非常的复杂难懂,并且难以定位问题

  • 降低数据库的性能(数据库不应该执行除 SQL 外的其他逻辑操作)


避免使用预留字段


  • 无法准确预测字段类型

  • 增加后期维护成本


反范式设计


  • 不必完全遵守古板的三大范式,对范式进行违反,用空间换时间

  • 对数据进行有计划的冗余,可以达到减少关联,提高性能和效率


尽量避免使用 Null 字段

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
猴子都能懂的数据库避坑指南,还说你不会?,闭关在家37天“吃透”这份345页PDF