更小的通常更好

  • 更小的通常更快
  • 使用不同数据类型的时候,虽然存储的内容是完全一样的(数据大小必然是一样的),但是因为4k对齐的存在,两者实际上占用的空间是不一样的(一个大,一个小)
  • 使用不同数据类型的时候一定是有区别的
  • ORM能否映射,应该是可以的;这里只是强调在数据库中存储的空间尽量少

简单就好

  • 该是什么类型就用什么类型
  • 用整型存储ip
  • 用mysql自建类型存储日期,而不用字符型
  • 整型比字符的操作代价更低,字符的校验规则更复杂

尽量避免使用null

  • 数据库中null是否等于null
  • 不等于,所以不起作用
  • 查询中包含了null,对mysql来说是很难优化的
  • 因为可为null的一些列使得索引统计和值的比较都变得复杂
    • 包括判断
    • 比较
    • 优化
    • 索引
    • 都很麻烦
  • 坦白说,可为null的列改为not null带来的性能提升非常小,所以没有必要进行优化
  • 之前的项目可为空,就让他空着;假如此时要设计一个数据库,尽量让所有的列不为null
  • 实际应用中,不可避免地会使用到null(不可能让用户信息都填满)
  • 能不使用null,尽量不使用null,这是最重要的
  • 默认值、特殊值要慎重—->字符型可以用空字符串,不能用a之类的,因为他可能出现在用户数据之中
  • oracle中有空串吗?mysql是可以的
  • 如果能的话(有选择的话),尽量设置为非空not null;不能的话就那样,没有选择设置为null

实际类型的优化

  • 类型优化其实很重要
  • 类型设计得很好的话,表空间是比较省的
  • 设计得不好的话,比如只给类型而不指定长度的时候,默认是int(11)、varchar(255),这样会占用更多的存储空间,这样不好
  • 一定要存指定好的长度
  • ❓❓❓可以用数据字典???
  • sqlsever不知道(用的少???)
  • 字段的长度在定义表的时候最好明确规定,虽然没有什么影响
  • 用int、varchar等存储的时候都是占的几个字节,只要没有超过类型的范围就行了,那个长度只是显式地定义了一下
  • 定义的长度定义的是一个规范,实际上没有什么用,就是规定了最大长度是多少
  • 即使超过了但是未超过范围仍然是合理的,但是建议写好,者关乎到一些规范的东西(写死就行了)
  • 需要多少就写多少,只是做了一个数据格式的校验,前台输入的时候不要超过那个长度就行了!
  • 字符型和DECIMAL有用,而整型和浮点型没有用
  • 主要用在严格模式中(比较麻烦,一般不涉及那个东西)
  • 在严格模式中很多东西都会受到影响
  • 整型特殊—->他与底层实际存储的字节数挂钩,与长度无关
  • 而字符型,他的实际存储是与长度相关的

整型

  • tinyint、smallint、mediumint、int、bigint的大小分别为8、16、24、32、64位
  • 1字节、2字节、3字节、4字节、8字节

    字符型

  • char

    • 最后面的空格会被去掉,而varchar不会
    • oracle中仍然会有空格?
    • 最大长度255
    • 检索效率、写效率比varchar高,以空间换时间(空间范围有限,只能存255,不适合存中文字符或者其他特殊字符)
    • 一般没有什么意义,因为在程序中会使用trime去掉空格再比较
  • varchar
    • varchar(5)和varchar(255)保存同样的内容,硬盘存储空间相同,但内存空间占用不同,是指定的大小
    • 一页是4kb,从磁盘中读取数据时,一下子是读取页的整数倍
    • 4k对齐,os默认的,好像也可以自己设置
    • 磁盘预读
    • 内存占用空间比实际大小要大一些,除非大小刚好是4k的整数倍
    • 4.2k—->8k;9m—->12m
    • 4k非常有用,在索引中也很重要,读索引时读的是整个4k中的数据
  • text
    • 一般不会用
    • 可以这么用但是一般不建议
    • 可以把json存在里面???
    • 有富文本编辑器(编译器?)
    • 完全可以放到一个ftp文件系统中,要读取的话直接读ftp中的文件就行了,不用再访问数据库了,因为一般情况下(跨数据库的时候?)访问数据库的时候会有一些IO的问题,而且有缓存的话还要将其进行缓存,太麻烦了
    • 一般不要用他,用varchar和char就够了
  • blob
    • 一般不会用
    • 可以这么用但是一般不建议
    • 有富文本编辑器(编译器?)
  • varchar2(oracle中的数据类型)

时间戳

  • 时间戳有多种类型,选择哪一个的时候会关乎我们的精度
  • datetime
  • timestamp
  • date

使用枚举代替字符串类型

  • mysql存储枚举类型会非常的紧凑,会根据列表值的数据压缩到一个或者两个字节之中,mysql内部会将每个值在列表中的位置保存为整数,并且在表的.frm文件中保存“数字-字符串”映射关系的查找表
  • 比如保存性别:男和女,假如存成0和1,那么还要在业务层进行转换
  • 假如用枚举可以将这个转换过程放到数据库层面进行
  • 底层存储枚举类型的时候,实际上存储的是整型
    • select e+0 from table;
  • 还可以进行排序,排序是按照枚举字符串所对应的整型值进行排序的,这个整数值与定义表时定义枚举的具体值时的顺序有关!
  • ORM框架不报错吗???应该没问题
  • 枚举类型的where条件可以用整型也可以用字符串类型
    • fish、apple、dog都是显式形式
    • 是读取数据的时候直接通过.frm转换过来的,实际中存储的是整型
  • 枚举类型的枚举值千万不要命名为数字,例如将枚举型分别定义为“1”“2”“3”没必要就是找事
  • 学的是优化点,不是钻牛角尖和抬杠
  • 枚举很常用,判断业务表中有些列就是那几个固定的很常用的值,这样的话最好使用枚举,可以提高效率
  • 国家省市区、自己的心情状态就可以写死
  • 或者直接用数字整型表示枚举型,可以节省很多空间(提高效率,违背命名规范?)

特殊类型

  • ip地址
  • 通常用varchar(15)来存储ip地址,但是这样不行,效率太低
  • 可以用32位无符号整数来进行存储、判断与比较
  • inet_aton和inet_ntoa
  • 第一个将字符型转换为整型,第二个将整型转换为字符型
  • 整数范围—->21亿

合理使用范式和反范式

范式

  • 大型项目的表设计要遵循三范式
  • 三范式是为了解决数据冗余问题
  • 优点:
    • 范式更新通常比反范式快
    • 很少有重复数据
    • 范式化的数据比较小,可以直接放在内存中,操作比较快
  • 缺点:
    • 通常情况下需要进行关联操作
    • 一张表的数据分成多张表就需要进行连接了
  • 阿里规范中:假如有超过三张表的时候禁止使用join的方式
    • why?
      • 因为三张表join的时候,数据量比较大的话,join的过程会很慢
      • 实际问题具体情况具体分析,不要不管三七二十一就按阿里规范来
      • 因为有可能项目中的数据量达不到那种层次,join也会很快,不会受什么影响的,没必要纠结

反范式

  • 在有些场景中可能需要冗余一部分的数据(反范式)
  • 范式更新通常比反范式快
  • 优点:
    • 所有的数据都在一张表中,可以避免关联
    • 可以设计一个有效的索引
  • 缺点:
    • 表格内的冗余数据比较多,删除数据的时候会造成表中有些有用信息丢失

范式和反范式进行一个衡量选择即可

  • 没必要一定按照某一个标准来
  • 实际情况具体分析
  • 范式和反范式混合使用、配合使用

应用场景

image.png

  • 尽量避免全排序,因为全排序要将表全部放到内存中去,效率太低了
  • 可以采用数据直接放到一张表里面不用再做join关联的方式了或者采用索引的方式进行排序
  • mysql中索引底层的数据结构是b+树,b+树本身就是一棵有序树,只要在相应列上建立索引,就可以按照当前列直接进行排序,就不需要自己放到内存里面再进行一次排序了
  • 为什么写了limit之后就不用写order by了,为什么写了limit之后order by就失效了
    • 就是因为用到了索引的查询—->效率比较高
  • 不需要count统计,直接查询缓存衍生值
    • 需要考虑做count和update的成本高低问题
    • 做一个选择
  • 设计表的时候,范式或者反范式都行,不要严格限制,可以两种方式结合使用
  • 约定大于规范
  • 没有哪里说设计表的时候一定要按范式来,可以自由点
    • 需求就要这样设计,不违反规则即可
  • 空间换时间
  • 合理选择即可,没必要说一定要遵循三范式的原则


三范式

  • 列不可分
  • 不存在传递依赖
  • 其他列的值必须唯一依赖主键值