本章解释了如何优化 MySQL 的性能,并提供了实例。优化包括在几个层面上配置、调整和测量性能。根据你的工作角色(开发人员、DBA 或两者的组合),你可能在单个 SQL 语句、整个应用程序、单个数据库服务器或多个联网的数据库服务器层面上进行优化。有时你可以主动出击,提前做好性能计划,而其他时候你可能会在问题发生后对配置或代码问题进行排查。优化 CPU 和内存的使用也可以提高可扩展性,使数据库能够处理更多的负载而不至于变慢。
数据库的性能取决于数据库层面的几个因素,如表、查询和配置设置。这些软件构造会导致硬件层面的 CPU 和 I/O 操作,你必须尽量减少这些操作,并使之尽可能高效。当你从事数据库性能工作时,你首先要学习软件方面的高级规则和准则,并使用壁钟时间来测量性能。当你成为专家时,你会了解更多关于内部发生的事情,并开始测量诸如 CPU 周期和 I/O 操作。
典型用户旨在从他们现有的软件和硬件配置中获得最佳的数据库性能。高级用户寻找机会改进 MySQL 软件本身,或开发他们自己的存储引擎和硬件设备来扩展 MySQL 生态系统:
- 在数据库层面上进行优化
- 在硬件层面上的优化
-
在数据库层面上进行优化
使一个数据库应用变得快速的最重要因素是它的基本设计。
表的结构是否正确?特别是,列是否有正确的数据类型,每个表是否有适合工作类型的列?例如,经常进行更新的应用程序通常有许多表,但列数很少,而分析大量数据的应用程序通常有少数表,但列数很多。
- 正确的索引是否已经到位,以使查询有效?
- 你是否为每个表使用了合适的存储引擎,并利用了你所使用的每个存储引擎的优势和特点?特别是,选择一个事务性的存储引擎,如 InnoDB 或一个非事务性的,如 MyISAM,对性能和可扩展性非常重要。
注意:InnoDB 是新表的默认存储引擎。在实践中,先进的 InnoDB 性能特征意味着 InnoDB 表经常比简单的 MyISAM 表更出色,特别是对于一个繁忙的数据库。
- 每个表都使用适当的行格式吗?这个选择也取决于表所使用的存储引擎。特别是,压缩的表使用更少的磁盘空间,因此需要更少的磁盘 I/O 来读取和写入数据。压缩可用于 InnoDB 表的各种工作负载,也可用于只读的 MyISAM 表。
- 应用程序是否使用了适当的锁定策略?例如,在可能的情况下允许共享访问,以便数据库操作可以同时运行,在适当的时候要求独占访问,以便关键操作获得最高优先权。同样,存储引擎的选择也很重要。InnoDB 存储引擎可以处理大多数锁的问题,而不需要你的参与,从而使数据库有更好的并发性,并减少你的代码的实验和调整的数量。
用于缓存的所有内存区域的大小是否正确?也就是说,大到足以容纳经常访问的数据,但又不至于大到超过物理内存并导致分页。需要配置的主要内存区域是 InnoDB 的缓冲池和 MyISAM 的密钥缓存。
在硬件层面上的优化
任何数据库应用最终都会遇到硬件限制,因为数据库变得越来越繁忙。DBA 必须评估是否有可能调整应用程序或重新配置服务器以避免这些瓶颈,或者是否需要更多的硬件资源。系统瓶颈通常来自这些方面。
磁盘搜索:磁盘找到一块数据需要时间。对于现代的磁盘,其平均时间通常低于 10 毫秒,所以理论上我们可以在一秒钟内完成大约 100 次搜索。这个时间在新的磁盘上改善得很慢,而且对于一个单一的表来说很难优化。优化寻道时间的方法是将数据分配到一个以上的磁盘上。
- 磁盘读和写:当磁盘处于正确位置时,我们需要读取或写入数据。在现代磁盘中,一个磁盘至少可以提供 10-20MB/s 的吞吐量。这比寻道更容易优化,因为你可以从多个磁盘并行读取。
- CPU 周期:当数据在主内存中时,我们必须对其进行处理以得到我们的结果。与内存量相比,拥有大表是最常见的限制因素。但对于小表,速度通常不是问题。
- 内存带宽:当 CPU 需要的数据多于 CPU 缓存所能容纳的数据时,主内存带宽就成为一个瓶颈。这对大多数系统来说是一个不常见的瓶颈,但也是一个需要注意的问题。
平衡可移植性和性能
要在一个可移植的 MySQL 程序中使用面向性能的 SQL 扩展,你可以在语句中把 MySQL 特定的关键字包裹在/*! */
的注释定界符中。其他 SQL 服务器会忽略注释的关键字。关于编写注释的信息,见 Section 9.7, “Comments”