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
系统变量定义缓冲池实例的数量。 -
如果缓冲池太小,可能会导致过度churning,因为页面从缓冲池中刷新出来只是为了很快地再次需要。
-
如果缓冲池太大,可能会导致交换,因为内存竞争。
-
-
存储引擎接口使优化器能够提供关于记录缓冲区大小的信息,以便扫描估计将读取多行的记录。缓冲区大小可以根据估计的大小而变化。
InnoDB
使用这种可变大小的缓冲区功能来利用行预取,并减少锁定和B树导航的开销。 -
所有线程共享
MyISAM
键缓冲区。key_buffer_size
系统变量确定其大小。对于每个
MyISAM
表,服务器打开一次索引文件;对于每个并发线程访问表,数据文件打开一次。对于每个并发线程,表结构、每列的列结构和大小为3 *
的缓冲区被分配(其中N
N
是最大行长度,不包括BLOB
列)。一个BLOB
列需要五到八个字节加上BLOB
数据的长度。MyISAM
存储引擎维护一个额外的行缓冲区用于内部使用。 -
可以将
myisam_use_mmap
系统变量设置为1,以启用所有MyISAM
表的内存映射。 -
如果内部内存临时表变得太大(根据
tmp_table_size
和max_heap_table_size
系统变量确定),MySQL会自动将表从内存格式转换为磁盘格式,该格式使用InnoDB
存储引擎。你可以按照第10.4.4节“MySQL中的内部临时表使用”中所述增加允许的临时表大小。对于使用
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,因此不应该有内存泄露。