MySQL 内存使用之线程独享

在这里我们将介绍的是 MySQL 内存使用上的线程独享,线程独享内存主要用于各客户端连 接线程存储各种操作的独享数据,如线程栈信息,分组排序操作,数据读写缓冲,结果集暂 存等等,而且大多数可以通过相关参数来控制内存的使用量。

AD :

对于任何一个数据库管理系统来说,内存的分配使用绝对可以算的上是其核心之一了,

所以很多希望更为深入了解某数据库管理系统的人,都会希望一窥究竟,我也不例外。

从内存的使用方式 MySQL 数据库的内存使用主要分为以下两类

线程独享内存

全局共享内存

今天这篇文章暂时先分析 MySQL 中主要的 “ 线程独享内存 ” 的。

在 MySQL 中,线程独享内存主要用于各客户端连接线程存储各种操作的独享数据, 如线程栈信息,分组排序操作,数据读写缓冲,结果集暂存等等,而且大多数可以通过相关

参数来控制内存的使用量。

线程栈信息使用内存 (thread_stack) :主要用来存放每一个线程自身的标识信息,如线 程 id ,线程运行时基本信息等等,我们可以通过 thread_stack 参数来设置为每一个线程栈 分配多大的内存。

排序使用内存 (sort_buffer_size) : MySQL 用此内存区域进行排序操作( filesort ),完成 客户端的排序请求。当我们设置的排序区缓存大小无法满足排序实际所需内存的时候,

MySQL 会将数据写入磁盘文件来完成排序。由于磁盘和内存的读写性能完全不在一个数量 级,所以 sort_buffer_size 参数对排序操作的性能影响绝对不可小视。排序操作的实现原理请 参考: MySQL Order By 的实现分析。

Join 操作使用内存 (join_buffer_size) :应用程序经常会出现一些两表 (或多表) Join 的 操作需求, MySQL 在完成某些 Join 需求的时候( all/index join ),为了减少参与 Join 的 “ 被 驱动表 ” 的读取次数以提高性能,需要使用到 Join Buffer 来协助完成 Join 操作(具体 Join 实现算法请参考: MySQL 中的 Join 基本实现原理)。当 Join Buffer 太小, MySQL 不会 将该 Buffer 存入磁盘文件,而是先将 Join Buffer 中的结果集与需要 Join 的表进行 Join 操 作,然后清空 Join Buffer 中的数据,继续将剩余的结果集写入此 Buffer 中,如此往复。 这势必会造成被驱动表需要被多次读取,成倍增加 IO 访问,降低效率。

-----------------------------------------------------Page 1-----------------------------------------------------

顺序读取数据缓冲区使用内存 (read_buffer_size) :这部分内存主要用于当需要顺序读取 数据的时候,如无发使用索引的情况下的全表扫描,全索引扫描等。在这种时候, MySQL 按 照数据的存储顺序依次读取数据块,每次读取的数据快首先会暂存在 read_buffer_size 中, 当 buffer 空间被写满或者全部数据读取结束后,再将 buffer 中的数据返回给上层调用者, 以提高效率。

随机读取数据缓冲区使用内存 (read_rnd_buffer_size) :和顺序读取相对应 ,当 MySQL 进行非顺序读取(随机读取)数据块的时候,会利用这个缓冲区暂存读取的数据。如根据索

引信息读取表数据,根据排序后的结果集与表进行 Join 等等。总的来说,就是当数据块的 读 取 需 要 满 足 一 定 的 顺 序 的 情 况 下 , MySQL 就 需 要 产 生 随 机 读 取 , 进 而 使 用 到 read_rnd_buffer_size 参数所设置的内存缓冲区。

连接信息及返回客户端前结果集暂存使用内存 (net_buffer_size) :这部分用来存放客户 端连接线程的连接信息和返回客户端的结果集。当 MySQL 开始产生可以返回的结果集, 会在通过网络返回给客户端请求线程之前,会先暂存在通过 net_buffer_size 所设置的缓冲 区中,等满足一定大小的时候才开始向客户端发送,以提高网络传输效率。不过,

net_buffer_size 参数所设置的仅仅只是该缓存区的初始化大小, MySQL 会根据实际需要自 行申请更多的内存以满足需求,但最大不会超过 max_allowed_packet 参数大小。

批 量 插 入 暂 存 使 用 内 存 (bulk_insert_buffer_size) : 当 我 们 使 用 如

insert …

values(…),(…),(…)… 的方式进行批量插入的时候, MySQL 会先将提交的数据放如一个缓 存空间中,当该缓存空间被写满或者提交完所有数据之后, MySQL 才会一次性将该缓存空 间中的数据写入数据库并清空缓存。此外,当我们进行 LOAD DATA INFILE 操作来将文本 文件中的数据 Load 进数据库的时候,同样会使用到此缓冲区。

临时表使用内存 (tmp_table_size) :当我们进行一些特殊操作如需要使用临时表才能完 成的 Order By , Group By 等等, MySQL 可能需要使用到临时表。当我们的临时表较小(小 于 tmp_table_size 参数所设置的大小)的时候, MySQL 会将临时表创建成内存临时表,只 有当 tmp_table_size 所设置的大小无法装下整个临时表的时候, MySQL 才会将该表创建成 MyISAM 存储引擎的表存放在磁盘上。不过,当另一个系统参数 max_heap_table_size 的大 小还小于 tmp_table_size 的时候, MySQL 将使用 max_heap_table_size 参数所设置大小作 为最大的内存临时表大小,而忽略 tmp_table_size 所设置的值。而且 tmp_table_size 参数 从 MySQL 5.1.2 才开始有,之前一直使用 max_heap_table_size 。

上面所列举的 MySQL 线程独享内存仅仅只是所有线程独享内存中的部分,并不是全 部,选择的原则是可能对 MySQL 的性能产生较大的影响,且可以通过系统参数进行调节。

-----------------------------------------------------Page 2-----------------------------------------------------

由于以上内存都是线程独享,极端情况下的内存总体使用量将是所有连接线程的总倍

数。所以各位朋友在设置过程中一定要谨慎,切不可为了提升性能就盲目的增大各参数值,

避 免因 为内 存不 够而 产生 Out Of Memory 异 常或 者是 严重 的 Swap 交 换反 而降 低整 体性 能。

-----------------------------------------------------Page 3-----------------------------------------------------