MySQL 在磁盘上创建临时表。我该如何阻止?

use*_*431 32 mysql performance windows database-tuning temporary-tables

我们正在运行一个网站(Moodle),用户目前发现它很慢。我想我已经将问题追溯到 MySQL 在磁盘上创建临时表。我created_tmp_disk_tables在 Mysql Workbench 服务器管理中观察了这个变量,这个数字以大约 50 个表/秒的速度增加。经过一天的使用,created_tmp_disk_tables是> 100k。此外,内存似乎没有被释放。使用量不断增加,直到系统变得几乎无法使用,我们必须重新启动 MySQL。我几乎每天都需要重新启动它,从使用大约 30-35% 的可用内存开始,并以 80% 结束一天。

我在数据库中没有 blob,也无法控制查询,因此我无法尝试优化它们。我还使用了Percona 配置向导来生成配置文件,但是 my.ini 也没有解决我的问题。

问题

  1. 我应该更改什么来阻止 MySQL 在磁盘上创建临时表?我需要更改哪些设置?我应该给它扔更多的内存吗?

  2. 如何阻止 MySQL 占用我的内存?

编辑

我启用了slow_queries日志并发现查询SELECT GET_LOCK() 被记录为缓慢。快速搜索显示我在 PHP 配置 ( mysqli.allow_persistent = ON) 中允许持久连接。我关掉了这个。这降低了 MySQL 消耗内存的速度。它仍然在创建临时表。

我还检查了它key_buffer size是否足够大。我看着变量key_writes。这应该为零。如果没有,请增加key_buffer_size.I 有零key_reads和零,key_writes因此我认为key_buffer_size足够大。

我将tmp_table_sizemax-heap-table-size增加到 1024M,因为 created_tmp_disk_tables 的增加可能表明这些表无法放入内存。这并没有解决它。

参考:http : //www.mysqlperformanceblog.com/2007/08/16/how-much-overhead-is-caused-by-on-disk-temporary-tables/

编辑 2

如果您sort_merge_passes在 SHOW GLOBAL STATUS 输出中看到许多每秒,您可以考虑增加该sort_buffer_size值。我sort_merge_passes在一小时内有 2 个,所以我认为它sort_buffer_size足够大。

参考:Mysql 手册 sort_buffer_size

编辑 3

我已经按照@RolandoMySQLDBA 的建议修改了排序和连接缓冲区。结果显示在下表中,但我认为created_tmp_tables_on_disk仍然很高。更改值后,我重新启动了 mysql 服务器,并created_tmp_tables_on_disk在一天(8 小时)后检查并计算了平均值。还有其他建议吗?在我看来,有些东西不适合某种容器,但我无法弄清楚它是什么。

+---------------------+-------------+-------------+--------------------+
| Tmp_table_size,     | Sort_buffer | Join_buffer | No of created      |
| max_heap_table_size |             |             | tmp_tables on disk |
+---------------------+-------------+-------------+--------------------+
| 125M                | 256K        | 256K        |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 512K        | 512K        |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 1M          | 1M          |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 4M          | 4M          |  100k/h            |
+---------------------+-------------+-------------+--------------------+   
                                                                  
Run Code Online (Sandbox Code Playgroud)



这是我的配置:

+-----------------------+-----------------------+
|DATABASE SERVER        |WEB SERVER             |
+-----------------------+-----------------------+
|Windows Server 2008 R2 |Windows Server 2008 R2 |
+-----------------------+-----------------------+
|MySQL 5.1.48           |IIS 7.5                |
+-----------------------+-----------------------+
|4 Core CPU             |4 Core CPU             |
+-----------------------+-----------------------+
|4GB RAM                |8GB RAM                |
+-----------------------+-----------------------+
Run Code Online (Sandbox Code Playgroud)

附加信息

+--------------------+---------+
|PARAM               |VALUE    |
+--------------------+---------+
|Num of tables in Db |361      |
+--------------------+---------+
|Size of database    |2.5G     |
+--------------------+---------+
|Database engine     |InnoDB   |
+--------------------+---------+
|Read/write ratio    |3.5      |
|(Innodb_data_read/  |         |
|innodb_data_written)|         |
+--------------------+---------+
|Avg table size      |15k rows |
+--------------------+---------+
|Max table size      |744k rows|
+--------------------+---------+
Run Code Online (Sandbox Code Playgroud)

这个设置是给我的,所以我对它的控制有限。Web 服务器使用的 CPU 和 RAM 非常少,因此我将该机器排除在瓶颈之外。大多数 MySQL 设置源自配置自动生成工具。

我已经使用 PerfMon 监控了几天有代表性的系统。由此,我得出结论,并不是操作系统正在交换到磁盘。

My.ini

[client]
port=3306
[mysql]
default-character-set=utf8

[mysqld]
port=3306
basedir="C:/Program Files/MySQL/MySQL Server 5.1/"
datadir="D:/DBs/Data/"
default-character-set=utf8
default-storage-engine=INNODB
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
max_connections=125
query_cache_size=350M
table_cache=1520
tmp_table_size=125M
table-definition-cache= 1024
max-heap-table-size= 32M
thread_cache_size=38

MyISAM Specific options
myisam_max_sort_file_size=100G
myisam_sort_buffer_size=125M
key_buffer_size=55M
read_buffer_size=1024K
read_rnd_buffer_size=256K
sort_buffer_size=1024K
join_buffer_size=1024K


INNODB Specific options
innodb_data_home_dir="D:/DBs/"
innodb_additional_mem_pool_size=32M
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=16M
innodb_buffer_pool_size=2G
innodb_log_file_size=407M
innodb_thread_concurrency=8
Run Code Online (Sandbox Code Playgroud)

Rol*_*DBA 16

my.ini看了一下,我有两个建议

建议#1

我会在你的 my.ini

sort_buffer_size=4M
join_buffer_size=4M
Run Code Online (Sandbox Code Playgroud)

这将使一些连接和排序留在内存中。当然,一旦 aJOIN或 anORDER BY需要超过4M,它就会将页作为 MyISAM 表到磁盘。

如果您无法以 身份登录root@localhost,则使用以下命令重新启动 mysql

C:\> net stop mysql
C:\> net start mysql
Run Code Online (Sandbox Code Playgroud)

如果您可以以 root@localhost 身份登录,则无需重新启动 mysql 即可使用这些设置。

只需在 MySQL 客户端中运行它:

SET @FourMegs = 1024 * 1024 * 4;
SET GLOBAL sort_buffer_size = @FourMegs;
SET GLOBAL join_buffer_size = @FourMegs;
Run Code Online (Sandbox Code Playgroud)

建议#2

由于您的数据在 Drive 上D:,您可能在 Drive 上有磁盘 I/O C:

请运行此查询:

mysql> show variables like 'tmpdir';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tmpdir        | C:\Windows\TEMP |
+---------------+-----------------+
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

由于我在桌面上使用默认值运行 mysql,因此我的临时表正在写入 Drive C:。如果驱动器d是一个更好的磁盘驱动器相比C:,或许你可以映射临时表到驱动器D:通过设置TMPDIRmy.ini,如下所示:

tmpdir="D:/DBs/"
Run Code Online (Sandbox Code Playgroud)

由于tmpdir不是动态变量,因此您必须重新启动 mysql 。

试一试 !!!

更新 2013-11-29 10:09 美国东部时间

建议#3

鉴于 MySQL 在 Windows 中运行并且您无法触及核心包中的查询,我有两个想法必须一起完成。

IDEA #1:将数据库移到 Linux 机器上

你应该能够

  • 设置 Linux 机器
  • 在 Linux 机器上安装 MySQL
  • 在 Windows 中为 MySQL 启用二进制日志记录
  • mysqldump 将数据库转储到文本 SQL 文件
  • 将 SQL 文件加载到在 Linux 中运行的 MySQL
  • 设置从 MySQL/Windows 到 MySQL/Linux 的复制

IDEA #2:重新配置 Moodle 以指向 Linux 机器

Moodle 最初是为 LAMP 设计的。只需将配置文件更改为指向 Linux 机器而不是 localhost。

这是一个关于设置 MySQL 的旧 Moodle 2.3 文档的链接:http : //docs.moodle.org/23/en/Installing_Moodle#Create_an_empty_database

我确信最新的文档也可用。

将数据库迁移到 Linux 有什么意义???

这对临时表的情况有什么帮助???

然后我建议将 RAM 磁盘设置为临时表的目标文件夹

临时表的创建仍然会发生,但它会被写入 RAM 而不是磁盘。减少磁盘 I/O。

更新 2013-11-29 11:24 EST

建议 #4

我建议使用快速 RAID-0 磁盘 (32+ GB)重新访问SUGGESTION #2,将其配置为 Drive T:(T 代表 Temp)。安装这样的磁盘后,将其添加到my.ini

[mysqld]
tmpdir="T:\"
Run Code Online (Sandbox Code Playgroud)

需要重新启动 MySQL,使用

net stop mysql
net start mysql
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我故意说 RAID-0,这样您就可以获得比 RAID-1、RAID-10 更好的写入性能。tmp 表磁盘不是我会多余的东西。

如果不优化@RaymondNijland 一直在评论的查询,则无法以任何方式减少临时表的创建计数。SUGGESTION #3SUGGESTION #4提供加速临时表创建和临时表 I/O 作为唯一选择。


use*_*431 13

为了完整起见,我在这里回答我自己的问题

我会选择@RolandoMySQLDBA 作为首选答案,因为它给了我最多的提示,即使它实际上并没有解决我的问题。

以下是我的调查结果

结论

Windows 上的 MySQL 只是创建了大量临时表,通过修改配置文件的内容来调整 MySQL 并没有帮助。

细节

该表详细说明了我在执行任何查询之前分别在 my.ini 中修改的参数。在每次测试之间重新启动 MySQL。

我以原题中的my.ini为模板,然后按照下表一一修改了参数的值。

我使用JMeter生成 100 个并发 Web 请求(代表我们的使用情况),重复 10 次。Test因此,每个请求总共包含 1000 个请求。这导致了后续的数据库调用。这表明无论我们更改什么配置参数,MySQL 都会创建大量临时表。

+----+------------+-------+---------------+------------+
|Test|Parameter   |Value  |NumOfTempTables|Db Max Conn |
+----+------------+-------+---------------+------------+
| 1  |key_buffer_ | 25M   | 30682         | 29         |
|    |size        |       |               |            | 
+----+------------+-------+---------------+------------+
| 2  |key_buffer_ | 55M   | 30793         | 29         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 3  |key_buffer_ | 100M  | 30666         | 28         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 4  |key_buffer_ | 125M  | 30593         | 24         |
|    |size        |       |               |            | 
+----+------------+-------+---------------+------------+
| 5  |query_cache_| 100M  | 30627         | 32         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 6  |query_cache_| 250M  | 30761         | 26         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 7  |query_cache_| 500M  | 30864         | 83*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 8  |query_cache_| 1G    | 30706         | 75*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 9  |tmp_table_  | 125M  | 30724         | 31         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 10 |tmp_table_  | 250M  | 30689         | 90*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 11 |tmp_table_  | 500M  | 30792         | 28         |
|    |size        |       |               |            |  
+----+------------+-------+---------------+------------+
| 12 |Sort_buffer&| 256K  | 30754         | 28         |
|    |Join_buffer |       |               |            |
+----+------------+-------+---------------+------------+
| 13 |Sort_buffer&| 512K  | 30788         | 30         |
|    |Join_buffer |       |               |            | 
+----+------------+-------+---------------+------------+
| 14 |Sort_buffer&| 1M    | 30788         | 28         |
|    |Join_buffer |       |               |            | 
+----+------------+-------+---------------+------------+
| 15 |Sort_buffer&| 4M    | 30642         | 35         |
|    |Join_buffer |       |               |            |
+----+------------+-------+---------------+------------+
| 16 |innodb-     | 1G    | 30695         | 33         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            |
+----+------------+-------+---------------+------------+
| 17 |innodb-     | 2G    | 30791         | 28         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            | 
+----+------------+-------+---------------+------------+
| 18 |innodb-     | 3G    | 30719         | 34         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            |  
+----+------------+-------+---------------+------------+
Run Code Online (Sandbox Code Playgroud)

*三个运行的平均值

下图描述了不同配置所需的数据库服务器的内存量和 CPU。黑线表示最小值和最大值,蓝条表示起始值和结束值。最大内存4096M如问题中所示。

内存使用情况 CPU使用率