MySQL 分配缓冲区和缓存以提高数据库操作的性能。默认配置旨在允许 MySQL 服务器在具有大约 512MB RAM 的虚拟机上启动。您可以通过增加某些缓存和缓冲区相关系统变量的值来提高 MySQL 性能。您还可以修改默认配置以在内存有限的系统上运行 MySQL。
以下列表描述了 MySQL 使用内存的一些方式。在适用的情况下,会引用相关的系统变量。有些项目是特定于存储引擎或功能的。
InnoDB
缓冲池是一个内存区域,用于保存表的缓存InnoDB
数据、索引和其他辅助缓冲区。为了提高大容量读取操作的效率,缓冲池被划分为 页面,这些页面可能包含多行。为了提高缓存管理效率,缓冲池被实现为页面的链表;很少使用的数据使用 LRU 算法的变体从缓存中老化。有关更多信息,请参阅 第 17.5.1 节,“缓冲池”。缓冲池的大小对系统性能很重要
InnoDB
在服务器启动时使用malloc()
操作为整个缓冲池分配内存。innodb_buffer_pool_size
系统变量定义缓冲池的大小。通常,建议的innodb_buffer_pool_size
值是系统内存的 50% 到 75%。innodb_buffer_pool_size
可以在服务器运行时动态配置。有关更多信息,请参阅 第 17.8.3.1 节,“配置 InnoDB 缓冲池大小”。在具有大量内存的系统上,您可以通过将缓冲池划分为多个 缓冲池实例 来提高并发性。
innodb_buffer_pool_instances
系统变量定义缓冲池实例的数量。过小的缓冲池可能会导致页面从缓冲池中刷新出来后不久又需要再次使用,从而导致过度搅动。
过大的缓冲池可能会因为内存竞争而导致交换。
存储引擎接口使优化器能够提供有关要用于扫描的记录缓冲区大小的信息,优化器估计这些扫描可能会读取多行。缓冲区大小可以根据估计的大小而变化。
InnoDB
使用这种可变大小的缓冲功能来利用行预取,并减少闩锁和 B 树导航的开销。所有线程共享
MyISAM
键缓存。key_buffer_size
系统变量决定其大小。对于服务器打开的每个
MyISAM
表,索引文件只打开一次;对于访问该表的每个并发运行的线程,数据文件只打开一次。对于每个并发线程,将分配一个表结构、每个列的列结构和大小为3 *
的缓冲区(其中N
N
是最大行长度,不包括BLOB
列)。一个BLOB
列需要 5 到 8 个字节加上BLOB
数据的长度。MyISAM
存储引擎维护一个额外的行缓冲区供内部使用。可以将
myisam_use_mmap
系统变量设置为 1,以便为所有MyISAM
表启用内存映射。如果内部内存临时表变得过大(由
tmp_table_size
和max_heap_table_size
系统变量确定),MySQL 会自动将表从内存格式转换为磁盘格式,后者使用InnoDB
存储引擎。您可以按照 第 10.4.4 节“MySQL 中的内部临时表使用” 中的说明增加允许的临时表大小。对于使用
CREATE TABLE
显式创建的MEMORY
表,只有max_heap_table_size
系统变量决定表可以增长的大小,并且不会转换为磁盘格式。MySQL 性能模式 是一种用于在低级别监视 MySQL 服务器执行情况的功能。性能模式会动态地逐步分配内存,根据实际服务器负载扩展其内存使用量,而不是在服务器启动期间分配所需的内存。分配的内存一旦分配,在服务器重新启动之前不会释放。有关更多信息,请参阅 第 29.17 节“性能模式内存分配模型”。
服务器用于管理客户端连接的每个线程都需要一些线程特定的空间。以下列表指出了这些空间以及控制其大小的系统变量
堆栈(
thread_stack
)连接缓冲区(
net_buffer_length
)结果缓冲区(
net_buffer_length
)
连接缓冲区和结果缓冲区的大小最初都等于
net_buffer_length
字节,但会根据需要动态扩展到max_allowed_packet
字节。每个 SQL 语句执行完毕后,结果缓冲区会缩减至net_buffer_length
字节。当一个语句正在运行时,还会分配当前语句字符串的副本。每个连接线程都使用内存来计算语句摘要。服务器为每个会话分配
max_digest_length
字节。请参阅 第 29.10 节“性能模式语句摘要和采样”。所有线程共享相同的基准内存。
当不再需要某个线程时,分配给它的内存将被释放并返回给系统,除非该线程返回线程缓存。在这种情况下,内存将保持分配状态。
每个执行表顺序扫描的请求都会分配一个 读取缓冲区。
read_buffer_size
系统变量决定缓冲区的大小。当以任意顺序(例如,排序后)读取行时,可能会分配一个 随机读取缓冲区 以避免磁盘查找。
read_rnd_buffer_size
系统变量决定缓冲区的大小。所有连接都在一次传递中执行,并且大多数连接甚至不需要使用临时表。大多数临时表都是基于内存的哈希表。行长度较大(计算为所有列长度的总和)或包含
BLOB
列的临时表存储在磁盘上。大多数执行排序的请求都会分配一个排序缓冲区和零到两个临时文件,具体取决于结果集的大小。请参阅 第 B.3.3.5 节“MySQL 存储临时文件的位置”。
几乎所有解析和计算都在线程本地和可重用的内存池中完成。小型项目不需要内存开销,从而避免了通常缓慢的内存分配和释放。仅为意外的长字符串分配内存。
对于每个具有
BLOB
列的表,会动态扩展一个缓冲区以读取更大的BLOB
值。如果扫描表,缓冲区的大小将增长到与最大的BLOB
值相同。MySQL 需要内存和描述符来存储表缓存。所有正在使用的表的处理程序结构都保存在表缓存中,并以““先进先出””(FIFO)的方式进行管理。
table_open_cache
系统变量定义初始表缓存大小;请参阅 第 10.4.3.1 节“MySQL 如何打开和关闭表”。MySQL 还需要内存来存储表定义缓存。
table_definition_cache
系统变量定义了可以存储在表定义缓存中的表定义数量。如果使用大量表,则可以创建一个大型表定义缓存以加快表的打开速度。与表缓存不同,表定义缓存占用的空间更少,并且不使用文件描述符。FLUSH TABLES
语句或 mysqladmin flush-tables 命令会立即关闭所有未使用的表,并将所有正在使用的表标记为在当前执行的线程完成后关闭。这有效地释放了大部分正在使用的内存。FLUSH TABLES
在所有表都关闭之前不会返回。服务器会将
GRANT
、CREATE USER
、CREATE SERVER
和INSTALL PLUGIN
语句执行结果的信息缓存在内存中。相应的REVOKE
、DROP USER
、DROP SERVER
和UNINSTALL PLUGIN
语句不会释放此内存,因此对于执行了导致缓存的大量语句实例的服务器,缓存的内存使用量会增加,除非使用FLUSH PRIVILEGES
释放它。在复制拓扑中,以下设置会影响内存使用,可以根据需要进行调整
复制源上的
max_allowed_packet
系统变量限制源发送到其副本进行处理的最大消息大小。此设置默认为 64M。多线程副本上的系统变量
replica_pending_jobs_size_max
设置可用于保存等待处理的消息的最大内存量。此设置默认为 128M。内存仅在需要时分配,但如果您的复制拓扑有时处理大型事务,则可能会使用它。这是一个软限制,可以处理更大的事务。复制源或副本上的
rpl_read_size
系统变量控制从二进制日志文件和中继日志文件中读取的最小数据量(以字节为单位)。默认值为 8192 字节。将为从二进制日志和中继日志文件读取数据的每个线程(包括源上的转储线程和副本上的协调器线程)分配一个大小为此值的缓冲区。binlog_transaction_dependency_history_size
系统变量限制作为内存历史记录保存的行哈希数。max_binlog_cache_size
系统变量指定单个事务的内存使用上限。max_binlog_stmt_cache_size
系统变量指定语句缓存的内存使用上限。
ps 和其他系统状态程序可能会报告 mysqld 使用了大量内存。这可能是由不同内存地址上的线程堆栈造成的。例如,Solaris 版本的 ps 将堆栈之间未使用的内存计为已使用的内存。要验证这一点,请使用 swap -s
检查可用的交换空间。我们使用多个内存泄漏检测器(包括商业版和开源版)测试了 mysqld,因此应该没有内存泄漏。