【读过的书,留下的迹】高性能MySQL(第3版)

时间:2021-10-30 19:39:50

前言

  最近发现有时候看完一本书,时间久了容易忘记,看书不总结思考效果大打折扣,故打算写这一系列文章,一是为了整理书中的要点,帮助自己消化理解;二是勉励自己多看书思考。文章中不会把书中内容讲解的非常详细,只是总结概括,适合已经阅读过该书的读者。

第2章:MySQL基准测试

基准测试是针对系统设计的一种压力测试

  • 基准测试有两种主要的策略
    • 针对整个系统的整体测试,集成式(full-stack)
    • 单独测试MySQL,单组件式(single-component)

测试指标

  • 吞吐量:单位时间内的事务处理数
  • 响应时间或者延迟:测试任务所需的整体时间
  • 并发性
  • 可扩展性

基准测试常见错误

  • 使用真实数据的子集而不是全集
  • 使用错误的数据分布
  • 使用不真实的分布参数
  • 在多用户场景,只做单用户的测试
  • 在单服务器上测试分布式应用
  • 反复执行同一个查询
  • 没有检查错误

基准测试工具

  • MySQL Benchmark Suite(sql-bench):自带
  • sysbench:推荐使用,功能较多完善

第3章:服务器性能剖析

主要为了定位使性能低的位置,主要方法使专注测量服务器的时间花费在哪里

剖析MySQL查询

  • 剖析整个数据服务器
    • 通过慢查询日志记录查询:mysql设置,信息相对较少
    • 通过pt-query-digest分析tcpdump结果:信息相对较多
  • 对查询进行单独的剖析
    • show profile
      • set profiling = 1;
      • show profiles; // 显示所有查询的时间
      • show profile for query 1; // 显示查询1的详细时间开销
    • show status
      • 返回一些有用的计数器,如read、delete的次数等
      • flush status; // 清除统计,重新开始
    • 慢查询日志

诊断间歇性问题

  • show global status
    • 以较高的频率反复执行该命令捕获数据,如Threads_connected、Threads_running的变化
  • show processlist(主要查看线程状态)
    • 以较高频率反复执行该命令,观察是否有大量线程处于不正常的状态或者不正常的特征

一般推荐上述两种方法,应为开销很低,而且可以通过简单的shell脚本或者反复执行的查询来交互式的收集数据,观察服务器的情况

第4章:Schema与数据类型优化

数据类型选择原则

  • 更小的通常更好:执行更快,占用更少磁盘、内存、CPU缓存
  • 简单就好:操作需要更少的CPU周期
  • 尽量避免NULL:使得索引、索引统计和值的比较都更复杂

  • 整数类型

    • TINYINT:8位;SMALLINT:16位;MEDIUMINT:24位;INT:32位;BIGINT:64位
  • 实数类型
    • FLOAT:32位;DOUBLE:64位,浮点类型不精确
    • DECIMAL:精确
  • 字符串类型
    • VARCHAR:需要使用1至2个额外字节记录字符串长度
    • CHAR:固定长度,对于经常变更的数据更适用
    • BLOB:采用二进制存储很大的数据
    • TEXT:采用字符方式存储很大的数据
  • 日期和时间类型
    • DATETIME:1001年-9999年
    • TIMESTAMP:1970年-2038年

范式和反范式

  • 范式优点
    • 更新操作比反范式快
    • 很少重复数据,存储少
    • 检索数据时很少需要GROUP BY之类的
  • 范式缺点
    • 通常需要关联
  • 反范式
    • 查询速度快,单独的表更有效的索引策略

第5章:创建高性能的索引

索引类型

  • B-Tree索引

    • 适合:全键值、键值范围或键值前缀查找
    • 限制
      • 不是按索引最左列开始查找,无法使用
      • 不能跳过索引中的列
      • 若有范围查询,其右边所有列不能使用索引优化
  • 哈希索引

    • 只有精确匹配索引所有列才有效
    • 限制
      • 只包含哈希值和行指针,不存储字段值
      • 不按照索引值顺序存储
      • 不支持部分索引列匹配查找
      • 不支持范围
      • 哈希冲突很多的话,维护代价高

InnoDB引擎有一个特殊的功能叫做”自适应哈希索引”。当InnoDB某些索引值被使用得非常频繁时,它会在内存中基于B-Tree索引之上再创建一个哈希索引

索引的优点

  • 大大减少了服务器需要扫描的数据量
  • 帮助服务器避免排序和临时表
  • 将随即IO变为顺序IO

高性能索引策略

  • 独立的列
    • 查询中的列不是独立的,即索引列是表达式的一部分,或者函数的参数,则不能使用索引
  • 前缀索引
    • 对于BLOB、TEXT或者很长的VARCHAR类型的列,必须使用前缀索引
    • 前缀索引使索引更小、更快,但无法使用GROUP BY和ORFER BY,也无法覆盖扫描
  • 多列索引
    • 索引合并策略,一定程度上可以使用表上的多个单列索引来定位指定的行
    • 如过个and或者or条件
  • 合适索引列顺序
    • 原则:选择性最高的列放在索引最前列
  • 聚簇索引
    • 定义:在同一个地方保存了索引和数据行
    • 优点:
      • 把相关数据保存在一起
      • 数据访问更快
      • 使用覆盖索引扫描的查询可以直接使用页节点的主键值
    • 缺点
      • 如果不是IO密集型应用,聚簇没优势
      • 插入速度严重依赖插入顺序
      • 插入新行,或者主键更新时,面临页分裂问题
      • 可能导致全表扫描变慢


【读过的书,留下的迹】高性能MySQL(第3版)

  • 覆盖索引
    • 如果一个索引包含所有需要查询的字段的值,我们就称之为”覆盖索引”
    • EXPLAIN的EXTRA列显示Using index
  • 索引扫描排序
    • 如果EXPLAIN的type列显示index,说明采用索引扫描排序

维护索引和表

  • 找到损坏表:check table
  • 修复损坏表:repaire table
  • 更新索引统计信息:analyze table
  • 减少索引和数据碎片:optimize table

第6章:查询性能优化

  • 优化数据访问

    • 查询不需要的记录
    • 多表关联时返回全部列
    • 总是取出全部列
    • 重复查询相同的数据
  • 是否扫描额外的记录,三个指标

    • 响应时间
    • 扫描的行数
    • 返回的行数
  • 重构查询方式

    • 一个复杂查询还是多个简单查询
    • 切分查询,如把一个大的delete切分成多个
    • 分解关联查询,关联放在应用程序中

查询执行基础


【读过的书,留下的迹】高性能MySQL(第3版)

优化特定类型的查询

  • 优化count()查询
    • count() where id > 5 转化为 count() - count(*) where id <= 5
    • 使用近似值
  • 优化关联查询
    • 确保on或者using子句中的列有索引
    • 确保group by或者order by只涉及一列,才能使用索引
  • 优化子查询
    • 尽可能使用关联查询代替
  • 优化limit
    • 尽可能使用索引覆盖扫描,再根据需要做一次关联操作,对于偏移量很大的时候,效率提高很多
  • 优化union
    • 手工将where、limit、order by等子句下推到各个union子查询,以便优化器充分利用这些条件优化

第7章:MySQL高级特性

分区表

  • 使用场景

    • 表非常大以至于无法全部都放在内存中
    • 分区表的数据更容易维护
    • 可以分布存储在不同物理设备上
    • 备份、恢复独立分区
  • 什么情况会出问题

    • NULL会使分区过滤无效
    • 分区列和索引列不匹配
    • 选择分区的成本很高
    • 打开并锁住所有底层表的成本可能很高
    • 维护分区的成本可能很高

在MySQL内部存储代码

MySQL允许通过触发器、存储过程、函数的形式存储代码

  • 优点
    • 节省网络开销
    • 代码重用
    • 简化代码的维护和版本更新
    • 提升安全性
  • 缺点
    • MySQL没有好的调试开发工具
    • 存储代码效率相对较低
    • 部署复杂性
    • 服务器增加额外的压力

绑定变量

创建绑定变量SQL时,客户端向服务器发送了一个SQL语句原型,服务端收到这个SQL语句框架后,解析并存储这个SQL语句,返回客户端一个SQL语句处理句柄

  • 优点
    • 只需解析一次SQL
    • 某些优化器只需执行一次
    • 仅仅是参数,网络开销小,效率高
    • 安全
  • 缺点
    • 会话级别

全文索引

希望通过关键字的匹配来进行查询过滤。全文索引可以支持各种字符内容的搜索,也支持自然语言搜索和布尔搜索。具体的,对数据表的某一条记录,MySQL会将需要索引的列全部拼接成一个字符串,然后进行索引。相比其他索引,当insert、update和delete操作进行时,全文索引的操作代价很大

优化:提供一个好的停用词表;忽略一些太短的单词

查询缓存

很多数据库产品,对于相同类型的SQL可以跳过SQL解析和执行计划生成阶段;MySQL还有另外一种不同的缓存,缓存完整的select查询结果,即跳过解析、优化和执行阶段。

  • 查询缓存容易成为整个服务器的资源竞争单点
    • 靠全局锁作保护
  • 打开查询缓存对读写操作带来消耗
    • 读查询前需先检查是否命中缓存
    • 读查询,如果能被缓存,执行查询后需缓存
    • 写出数据时,对应表的缓存设置失效
  • 缓存碎片、内存不足、数据修改都会造成缓存失效