数据库与数据类型优化——《高性能Mysql》学习笔记1

1. 记住几条简单的原则

  • 更小的通常更好
    尽量使用正确存储数据的最小数据类型。更小的数据类型通常更快,因为他们占用更小的磁盘,内存和CPU缓存,并且处理时需要的CPU周期也更少。
  • 简单就好
    简单数据类型的操作通常需要更少的CPU周期。

    1. 例如,整型比字符操作代价更低,因为字符集和校对规则使字符比较复杂与整型比较。
    2. 例如,使用Mysql的內建类型而不是字符串来存储日期和时间。
    3. 例如:用整型存储IP地址。
  • 尽量避免NuLL
    通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值。如果查询中包含可为NULL的列,不利于MYSQL的优化(索引管理因为NULL变得复杂)。
    但是通常把NULL的列改为NOT NULL的性能提升比较小,如果计划在列上建索引,尽量避免设计可为NULL的列。


2. 基础数据类型详解

1. 整数类型

TINTINT SMALLINT MEDIUMINT INT BIGINT
8 16 24 32 64
  • 以上为存储整数的可用类型以及相应的存储位数, 范围为-2^(n-1)到2^(n-1)-1,n为存储位数。
  • 整数类型的无符号UNSIGNED属性是可选的,表示不可为负,可以使正数的上限提高一倍。但是有符号和无符号使用相同的存储空间,根据实际情况选择。
  • MYSQL可以为整数类型指定宽度,例如INT(11),但是对于存储和计算的性能来说,INT(1)和INT(20)没有区别,只有显示字符个数之间的差别。

2. 实数类型

  • 主要分为两类:浮点数和DECIMAL,都支持指定精度。
  • 浮点类型FLOAT和DOUBLE分别占4字节和8字节,MYSQL使用DOUBLE作为内部浮点计算的类型。
  • DECIMAL计算开销大,尽量避免使用。

3. 字符串类型

VRCHAR

  • 存储可变长字符串,比定长节省空间,对性能也有帮助。
  • 需要使用1个或2个字节记录字符串长度,列长度小于等于255,则只用1个字节记录长度,否则是两个;
  • 因为行可能边长,在UPDATE时若空间增长,可能需要额外的工作(页分裂),容易产生碎片。
  • 推荐使用VARCHAR的情况:
    1. 字符串序列的最大长度比平均长度大很多。
    2. 列更新比较少
    3. 使用了UTF-8这样复杂的字符集,每个字符都使用不同的字节数存储。

CHAR

  • 定长,适合存储很短的字符串,或者字符串所有值都接近同一个长度。
  • 对于经常更新的数据,CHAR更合适,不容易产生碎片,虽然更占用空间。
  • 跟VARCHAR比,CHAR不需要额外记录长度,所以非常短的列适合用CHAR。
  • 对于CHAR来说,如果长度不足的话,存储时MYSQL会用空格补全,检索时自动剔除末尾空格;对于VARCHAR来说,MYSQL5.0及更高版本会保留末尾空格,而老版本不会。


BINARY和VARBINARY

  • 存储二进制字符串。二进制字符串存储的是字节码,采用\0填充
  • BINARY和VARBINARY适合用来存储二进制数据,二进制比较 比普通字符串的比较的效率要高。


BIOB和TEXT

  • 都为存储很大的数据而设计的,BOLB采用二进制存储,TEXT采用字符方式存储。

补充:使用枚举(ENUM)代替字符串

  • 如果字符串的值固定几种的话,适合用枚举代替字符串
  • 枚举内部保存为整数,能够节省空间,提高性能。

4. 日期和时间类型

  • DATETIME:把日期时间封装到格式为‘YYYYMMDDHHMMSS’的整数中,精确到秒,使用8字节存储,与时区无关。
  • TIMESTAMP:保存了1970年1月1日午夜(格林尼治标准时间)到现在的秒数的秒数,使用4个字节存储,只能表示1970年到2038年,显示的值依赖时区,TIMESTAMP列默认为NOT NULL。
  • 推荐使用TIMESTAMP,因为它用整数类存储,方便计算机计算,空间效率高。
  • DATE:3字节,日期,格式为YYYYMMDD
  • YEAR:1字节,年份,格式为YYYY
  • TIME:3字节,时间,格式为HHMMSS

5. 位数据类型

  • BIT: 内部使用整数存储,但是实际情况又比较复杂,不推荐使用。
  • SET:用一系列打包好的位的集合来表示,缺点是列定义的代价高(需要用ALTER TABLE),并且在SET列无法使用索引
  • SET使用案例:保存基于权限的控制访问表:
    这里写图片描述

标识列数据类型的选择

  • 最好选择是整数类型,速度快,并且可以AUTO_INCREMENT
  • 避免使用字符串做标识,消耗空间,比整数慢。
  • 随机字符串(例如UUID()产生)会任意分布在很大的空间内,导致INSERT和SELECT变慢。

3. MYSQL数据库设计的常见问题

1. 太多的列

  • MYSQL的服务器和存储引擎之间通过行缓存格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。从行缓冲中将编码后的列转换成行数据结构的操作代价是十分高的,转换的代价取决于列的数量。

2. 太多的关联

  • MYSQL限制了关联操作最多只能有61张表,如果希望查询执行快而且并发性能好,单个查询的表关联数目最好在12个以内。

3. 过度使用枚举

  • 导致设计凌乱;增加一次枚举就要ALTER TABLE,代价可能很高。

4. 范式与反范式的选择

范式的优点与缺点

优点:

  • 范式的更新操作比反范式快
  • 数据冗余少
  • 范式化的表更小,可以更好的放在内存里,执行操作更快。
  • 重复数据少意味着更少使用DISTINCT以及GROUP BY语句

缺点:

  • 通常需要关联,关联可能使一些索引无效。

反范式的优点与缺点

优点:

  • 数据集中在一张表,避免关联
  • 查询比关联快,避免了随机I/O
  • 单独的表能更有效的使用索引策略

最佳选择:混用范式化和反范式化

  • 完全的范式化和反范式化都不可取
  • 推荐采用部分范式化,复制或者缓存,在不同表中存储相同的特定列,允许部分数据冗余,利用冗余做更高效率的查询

实例:

  • 对于需要统计数量的情况,可以增加一个字段来存储数量并实时更新,避免昂贵的统计查询。
  • 缓存表与汇总表:建立一张简单的表保存衍生的数据。
  • 计数器表:解决并发问题。例如统计网站点击数量:
CREATE TABLE hit_counter(
     slot tinyint unsigned not null primary key,
     cnt int unsigned not null
)ENGINE=InnoDB;
  • 然后预先在这张表增加一百行数据,网站被点击一次时,选择一个随机的槽(slot)进行更新
UPDATE hit_counter SET cnt = cnt + 1 WHERE slot = RAND()*100;
  • 要获得统计结果,需要这样查询
SELECT SUM(cnt) FROM hit_counter

参考 :《高性能Mysql》

猜你喜欢

转载自blog.csdn.net/huanglu20125/article/details/79367222