数据库优化策略小结

  • 一数据类型的优化
    • 1MySQL数据类型
    • 2优化策略
  • 二索引优化
    • 1索引类型
    • 2高性能索引策略
  • 三查询优化
    • 1优化数据访问
    • 2从好到坏的where条件应用
    • 3重构查询

一、数据类型的优化

(1)MySQL数据类型

  • 整数类型:
    • TinyInt,存储空间8, 字节长度1;
    • SmallInt, 存储空间16, 字节长度2;
    • MediumInt,存储空间24, 字节长度3;
    • Int,存储空间32, 字节长度4;
    • BigInt,存储空间64, 字节长度8;
  • 实数类型:
    • Float:字节长度8,单精度浮点数;
    • Double:字节长度16,双精度浮点数;
    • Decimal:未打包的浮点数,计算中会转化为Double;Decimal 相比于 Float 和 Double 需要额外的空间和计算开销,因此尽量只在对小数进行精确计算时才使用,例如存储财务数据。在数据量比较大的时候,可以考虑使用 BigInt 代替 Decimal,将需要存储的货币单位根据小数的位数乘以相应的倍数即可。  
  • 字符串类型:
    • VarChar:存储可变长字符串,需要一个或两个额外字节记录字符串长度。适用于:字符串列的最大长度比平均长度大很多;列的更新很少(所以碎片不是问题);使用了UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。
    • Char:定长,根据定义的字符串长度分配足够的空间。Char 适合存储很短的字符串,或者所有值都接近同一个长度。如:存储密码的MD5值(这是一个定长的值);经常变更的数据(定长的 Char 类型不容易产生碎片);非常短的列,比如用 char(1) 来存储只有Y和N的值,如果采用单字节字符集只需要一个字节,但是 varchar(1) 却需要两个字节(还有一个记录长度的额外字节)。
  • 时间类型
    • DATETIME:使用8字节存储空间,将日期和时间装到格式为YYYYMMDDHHMMSS的整数中;
    • TIMESTAMP:使用4字节存储空间,显示的值依赖于时区。尽量使用它,因为它的空间效率更好。

(2)优化策略

  • 更小的通常更好
    • 更小的通常更快,因为它占用更小的磁盘、内存和cpu缓存,且处理时需要的cpu周期更小;
    • 但是要确保没有低估需要存储的值的范围。
  • 简单就好
    • 简单的数据类型操作需要更少的cpu处理周期;
    • 如:整型比字符串代价更低、MySQL内建类型(date,time,datetime)而非字符串来存储时间、用整型存储IP地址。
  • 尽量避免使用NULL
    • 通常最好指定列为NOT NULL,除非真的需要存储NULL值;
    • 因为如果查询中包含可为 NULL 的列,对 MySQL 来说更难优化,因为可为 NULL 的列使得索引、索引统计和值比较都更复杂;可为 NULL 的列会使用更多的存储空间,在MySQL里也需要特殊处理;当可为 NULL 的列被索引时,每个索引记录需要一个额外的字节。

二、索引优化

(1)索引类型

  • B-Tree索引:
    • 通常意味着所有值按顺序存储,并且每一个叶子叶到根的距离相等;
    • 能加快访问速度,因为存储引擎不需要全表扫描来捕获需要的数据,而是从索引的根节点开始进行搜索;
    • 对索引顺序存储,所以很适合查找范围数据
  • B-Tree索引有效的查询类型:
    • 全值匹配:和索引中所有列进行匹配;
    • 匹配最左前缀:只使用索引第n列匹配;
    • 匹配列前缀:只匹配某一列值的开头部分;
    • 匹配范围值:某一列在xx和xxx之间的值;
    • 精确匹配某一列,范围匹配另一列:某一列全匹配,另一列范围匹配;
    • 只访问索引的查询:只访问索引,不访问数据行。
  • B-Tree索引的限制:
    • 如果不是按照索引的最左列查找,则无法使用索引;
    • 不能跳过索引中间的列;
    • 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找;(如果范围查询有限,建议使用多个等于代替范围查询)。
  • 哈希索引:
    • 基于哈希表实现,只有精确匹配索引所有列的查询才有效;
    • 对于每一行数据,存储引擎都会对所有索引列计算一个哈希码,哈希索引将所有哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针;
  • 哈希索引的限制:
    • 只包含哈希值和行指针,不存储字段,所以不能使用索引中的值避免读取行;
    • 不是按索引值顺序存储,所以不能排序;
    • 不支持部分索引列匹配查找;
    • 访问哈希索引的速度非常快,除非出现很多哈希冲突,出现很多哈希冲突的话,一些索引维护的代价非常大;
  • 哈希索引的应用:
    • InnoDB“自适应哈希索引”:某些索引值被引用的非常频繁,他会在内存中基于B-Tree索引的基础上创建一个哈希索引。

(2)高性能索引策略:

  • 索引的优点:
    • 索引可以大大减少数据库表的扫描量
    • 索引可以帮助服务器避免排序和临时表
    • 索引可以将随机I/O变成顺序I/O
  • 索引选择:

    • 前缀索引:使得索引更小,更快(比如要索引很长的字符串),但是无法做GROUP BY和ORDER BY操作,也无法覆盖扫描;
    • 索引列顺序:经验法则是将选择性最高的放在最前面;
  • 聚簇索引:实际上是一种数据的存储方式

    • 数据航存放在索引的叶子结点,且数据行和相邻的键值紧凑地存放在一起
    • 优点:
      • 可以将相关数据保存在一起,减少磁盘I/O
      • 索引和数据保存在一个B-Tree,数据访问更快
      • 使用覆盖索引的扫描时可以直接使用主键
    • 缺点:
      • 插入速度依赖于插入顺序,最好是按照主键顺序插入
      • 更新列代价很高
      • 插入行可能导致页分裂

三、查询优化

(1)优化数据访问

  • 避免查询不需要的记录:使用limit;
  • 避免多表查询查询所有列:不要随意使用select * ;
  • 重复查询相同数据:采用缓存;

(2)从好到坏的where条件应用

  • 最佳:存储引擎层在索引中使用where过滤不匹配的记录
  • 次佳:使用索引覆盖扫描,直接从索引中过滤不需要的记录并返回,在服务器层完成
  • 最次:先从数据表中返回数据,然后过滤,需要回表查询

(3)重构查询

  • 一个复杂查询改为多个简单查询
  • 切分查询:
    • 对大查询“分而治之”,减少锁持有的时间
    • 例如删除过期记录,每次LIMIT 10000,否则可能一次锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞很多小但是重要的查询;
  • 分解关联查询:
    • 让缓存效率更高;
    • 减少锁的竞争;
    • 应用层关联便于表的拆分,更容易做到高性能和可扩展;
    • 减少冗余记录查询;

参考文献:《高性能MySQL》

你可能感兴趣的:(数据库)