高性能MySql学习笔记-附录

A. MySQL分支与变种

Percona Server

  • Percona Server 是个与 MySQL 向后兼容的替代品,任何运行在 MySQL 上的都可以运行在 Percona Server 上。
  • Percona Server 包括 Percona XtraDB 存储引擎,即改进版本的 InnoDB,这同样是个向后兼容的替代品。

MariaDB

Drizzle

  • Drizzle 是真正的 MySQL 的分支,而非只是个变种或增强版本。它并不与 MySQL 兼容。

B. MySQL服务器状态

系统变量

  • MySQL 通过 SHOW VARIABLES SQL命令展示系统变量。

SHOW STATUS

  • SHOW STATUS命令会显示每个服务器变量的名字和值。这些变量是只读的。如果使用 SQL 命令,可以使用 LIKE 或 WHERE 来限制结果。可以从 INFORMATION_SCHEMA.GLOBAL_STATUS 和 INFORMATION_SCHEMA.SESSION_STATUS 表中查询。

  • 现在SHOW STATUS默认展示会话变量,如果查看全局变量,则需要运行SHOW GLOBAL STATUS

  • 线程和连接统计。这些变量用来跟踪尝试的连接、退出的连接、网络流量和线程统计等。

  • 二进制日志状态。Binlog_cache_use和 Binlog_cache_disk_use状态变量显示了在二进制日志缓存中有多少事务被存储过,以及多少事务因超过二进制日志缓存而必须存储到一个临时文件中。

  • 命令计数器。Com_*变量统计了每种类型的 SQL 或 C API 命令发起过的次数。

  • 临时文件和表

  • 句柄操作。句柄 API 是 MySQL 和存储引擎之间的接口。Handle_* 变量用于统计句柄操作。

  • MyISAM 键缓冲。 Key_*变量包含度量值和关于 MyISAM 键缓冲的计数。

  • 文件描述符。对于 MyISAM 存储引擎,Open_*变量揭示 MySQL 每隔多久打开每个表的.frm、.MYI 和.MYD 文件。InnoDB 保持所有的数据在表空间文件中,所以对于 InnoDB这些变量并不准确。

  • 查询缓存。查询 Qcache_*状态变量可以检查查询缓存。

  • SELECT 类型。Select_*变量是特定类型的 SELECT 查询的计数器。它们展示各种查询计划的 SELECT 查询比率。

  • 排序。当 MySQL 不能使用索引获取预先排序的行,则必须使用文件排序,这会增加 Sort_*状态变量。

  • 表锁。Table_locks_immediate 和 Table_locks_waited 变量展示有多少锁被立即授权,有多少锁需要等待。

SHOW ENGINE INNODB STATUS

  • InnoDB 存储引擎在SHOW ENGINE INNODB STATUS输出中,它的输出是单独的一个字符串,分为很多小段。
  • SEMAPHORES。包含了两种数据:事件计数器、以及可选的当前等待线程的列表。如果有高并发的工作负载,则需要关注该端。
  • LATEST FOREIGN KEY ERROR。展示服务器最新的外键错误。
  • LATEST DETECTED DEADLOCK。展示服务器内最新的死锁信息。
  • TRANSACTIONS。包含关于 InnoDB 事务的总结信息,紧随其后是当前活跃事务列表。
  • FILE I/O。FILE IO 部分显示的是 IO 辅助线程的状态,还有性能计数器的状态。
  • INSERT BUFFER AND ADAPTIVE HASH INDEX。显示关于插入缓存和自适应哈希索引的状态。
  • LOG。显示关于 InnoDB 事务日志(重做日志)子系统的统计。
  • BUFFER POOL AND MEMORY。显示关于 InnoDB 缓冲池机器如何使用内存的统计。
  • ROW OPERATIONS

SHOW PROCESSLIST

  • 进程列表是当前连接到 MySQL 的连接或线程的清单。SHOW PROCESSLIST 列出了这些线程,以及每个线程的状态信息。Command 和 State 列真正表明了线程的状态。

SHOW ENGINE INNODB MUTEX

  • 改命令返回 InnoDB 互斥体的详细信息,每个互斥体都保护着代码中一个临界区。

复制状态

  • MySQL 有几个命令用以监测复制。在主库上执行SHOW MASTER STATUS 可显示主库的复制状态和配置。输出包含了主库当前的二进制日志位置。通过SHOW BINARY LOGS可以获取到二进制日志的列表。通过SHOW BINLOG EVENTS可以查看二进制日志中的事件。在备库上执行 SHOW SLAVE STATUS查看复制的状态和配置。

INFORMATION_SCHEMA

  • INFORMATION_SCHEMA 库是一个 SQL 标准中定义的系统视图的集合。能够以标准的 SQL 来进行查询。

Performance Schema

  • Performance Schema是 MySQL 增强仪表的新的汇总处。默认情况下,Performance Schema是禁用的,需要打开并且使其在一个想要手机的特定的仅表点启用。

C. 大文件传输

一个简单的示例

  • 在server1的源服务器,将文件进行压缩,并使用scp方法复制到server2
$ gzip -c /backup/mydb/mytable.MYD > mytable.MYD.gz
$ scp mytable.MYD.gz root@server2:/var/lib/mysql/mydb/
  • 在server2执行如下命令,进行解压
$ gunzip /var/lib/mysql/mydb/mytable.MYD.gz
  • 这个方法效率不高,因为在server1上gzip需要读写,scp在server1上读在server2上写,gunzip在server2上既要读又要写。

一步到位的方法

  • 下面这个方法将压缩、复制文件和在传输的另一端解压缩文件全部放在一个步骤里完成。这个方法只需要在server1读,在server2上写。
$ gzip -c /backup/mydb/mytable.MYD | ssh root@server2 "gunzip -c - > /var/lib/mysql/mydb/mytable.MYD" 

避免加密的系统开销

  • SSH 部署跨网传输数据的最快方法,因为它增加了加解密的系统开销。如果不需要加密,可以使用netcat把“裸数据”进行跨网传输。

其他选项

  • 另一个选项是rsync。rsync易于在源和目标直接做镜像,并且还可以断点续传。但是,如果它的二进制差异算法无法被很好的发挥时,它不太会得到很好应用。

D. EXPLAIN

调用 EXPLAIN

  • 在 SELECT 关键字前增加 EXPLAIN 这个词,MySQL 在执行查询时,这个标记会使其返回关于在执行计划中的每一步的信息,而不是执行它。
  • EXPLAIN 语句并不总是不执行查询,如果在 FROM 子句中包含子查询,那 MySQL 实际会执行子查询。
  • EXPLAIN 只是一个近似结果,有时其结果与真相相差甚远。

EXPLAIN 中的列

  • id 列。id 列包含一个编号,标识 SELECT 所属的行。如果语句中没有子查询或联合,那么只会有唯一的 SELECT,于是每一行在这个列中都将显示一个1。否则,内层的 SELECT 语句一般会顺序编号。

  • select_type 列。这一列展示了对应行是简单查询还是复杂查询,如果是复杂查询,那么是三种复杂类型中的哪一种。SIMPLE值意味着查询不包括子查询和 UNION。如果查询有任何复杂的子部分,则最外层部分标记为 PRIMARY。其他部分标记如下:

    • SUBQUERY。包含在 SELECT 列表中子查询的 SELECT。(不在 FROM 子句中)。
    • DERIVED。包含在 FROM 子句的子查询中的 SELECT。
    • UNION。在 UNION 中的第二个和随后的 SELECT 被标记为 UNION。
    • UNION RESULT。用来从 UNION 的匿名临时表中检索结果的 SELECT 被标记为 UNION RESULT。
  • table 列。展示对应行正在访问哪个表。

  • type 列。代表访问类型,也就是 MySQL 决定如何查找表中的行。如下为重要的访问方法,依次从差到优。

    • ALL。俗称全表扫描,代表 MySQL 必须扫描整张表来查询数据。
    • index。这个同样是全部扫描,只不过扫描表时按索引顺序进行,而不是行顺序。它的主要优点是避免了排序,缺点是要承担按索引排序读取整个表的开销,因为这往往是随机读取。
    • range。范围扫描就是一个有限制的索引扫描。这比全索引扫描好一些,因为不用遍历全部索引。常见的范围扫描是带有 BETWEEN 或在 WHERE 子句中带有比较的查询。
    • ref。这是一种索引访问,返回所有匹配某个单个值的行,当然也可能有多个符合条件的行。
    • eq_ref。这也是一种索引访问,相比 ref,MySQL 确定最多只返回一条符合条件的记录。
    • const,system。当 MySQL 能对查询的某部分优化转化为常量时,则使用此种访问类型。
    • NULL。 这种访问方式意为着 MySQL 能够在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。
  • possible_keys 列。这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的,这里出现的索引不代表 MySQL 最终会选择他们。

  • key 列。这一列展示 MySQL 最终选择了哪个索引来优化对该表的访问。如果该索引没有出现在 possible_keys 列中,那么 MySQL 选用它是由于另外的原因——例如,它可能选择了一个覆盖索引,哪怕没有 WHERE 子句。

  • key_len列。该列显示了 MySQL 在索引里使用的字节数。如果 MySQL 正在使用的只是索引里的某些列,可以根据这个值进行推算,比如一个联合索引,但是只使用了其最左侧列的情况。

  • ref列。这一列展示了之前的表在 key 列记录的索引中查找值所用的列或常量。

  • rows 列。这一列是 MySQL 估计为了找到所需的行而要读取的行数。它不是 MySQL 认为最终要从表里读取出来的行数,而是 MySQL 为了查询而必须扫描的行数。

  • filtered列。它显示的是针对表里符合某个条件(WHERE 子句或联接条件)的记录数的百分比所做的一个悲观估算,优化器只有在使用 ALL、index、range、和 index_merge 访问方法时才会使用这一估算。

  • Extra 列。这一列显示不适合在其他列显示的额外信息。常见的重要的值如下:

    • Using index。表示 MySQL 将使用覆盖索引,以避免访问表。不要把覆盖索引和 index 访问类型弄混了。
    • Using where。这意味着 MySQL 服务器将在存储引擎检索行后再进行过滤。又是 Using where 的出现就是一个暗示:查询可受益于不同的索引。
    • Using temporary。代表 MySQL 在对查询结果排序时会使用一个临时表。
    • Using filesort。这意味着 MySQL 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。

MySQL5.6中的改进

  • MySQL 5.6中包括一个对 EXPLAIN 的重要改进:能对类似 UPDATE、INSERT 等的查询进行解释。

E. 锁的调试

服务器级别的锁等待

  • 锁等待可能发生在服务器级别或存储引擎级别。服务器级别的锁有表锁、全局锁、命名锁、字符锁等类型。
  • 表锁
    • 表锁可以是显式的,也可以是隐式的。显示的锁用 LOCK TABLES 创建。可以执行如下命令,在 sakila.film 上获取一个显式的锁:LOCK TABLES sakila.film READ;
    • 如果在另一个会话中也获取这个表的锁,查询将被挂起并且不会执行:LOCK TABLES sakila.film WRITE;
    • 使用命令SHOW PROCESSLIST;可以看到等待线程的状态是 Locked。
    • 服务器在查询过程中也会隐式地锁住表。一个长时间的查询即可将表锁住:SELECT SLEEP(30) FROM sakila.film LIMIT 1;当这个查询运行时,尝试再次锁住 film 表将会因为隐式锁而挂起。
    • 隐式锁和显式锁会阻塞,隐式锁也会相互阻塞。
  • 全局读锁
    • MySQL 服务器实现了一个全局读锁,可以如下获取该锁:FLUSH TABLES WITH READ LOCK;
    • 如果此时在另一个会话中尝试获取表锁,将会被挂起。而等待线程在 SHOW PROCESSLIST 中的状态将会是 Waiting for release of readlock,代表查询在等待一个全局读锁而不是表级锁。
  • 命名锁
    • 命名锁是一种表锁:服务器在重命名或删除一个表时创建。命名锁与普通的表锁相冲突,无论是显式还是隐式的。
  • 用户锁
    • 在服务器中实现的最后一种锁是用户锁,它是一个命名互斥量,需要指定锁的名称字符串,以及等待超时秒数。SELECT GET_LOCK('my lock', 100);
    • 如果另一个线程尝试锁相同字符串,它将被挂起直到超时。

InnoDB 的锁等待

  • InnoDB 在SHOW INNODB STATUS的输出中显示了一些锁信息。也可以通过查询 INFORMATION_SCHEMA 表的方式来显露 InnoDB 的事务和锁。
posted @ 2021-12-30 03:11  员力  阅读(70)  评论(0编辑  收藏  举报