MySQL在进行多个连接时出现“tmp表键文件不正确”的错误。

60

我不经常来这里寻求帮助,但是我对此感到非常沮丧,并希望有人曾经遇到过这个问题。

每当我尝试使用多个连接从表中获取记录时,就会出现以下错误:

#126 - Incorrect key file for table '/tmp/#sql_64d_0.MYI'; try to repair it

所以这个查询将会产生错误:

SELECT * FROM `core_username`
INNER JOIN `core_person` ON (`core_username`.`person_id` = `core_person`.`id`)
INNER JOIN `core_site` ON (`core_username`.`site_id` = `core_site`.`id`)
ORDER BY `core_username`.`name` ASC LIMIT 1

但这一个不会:

SELECT * FROM `core_username`
INNER JOIN `core_person` ON (`core_username`.`person_id` = `core_person`.`id`)
ORDER BY `core_username`.`name` ASC LIMIT 1

这个也不会:

SELECT * FROM `core_username`
INNER JOIN `core_site` ON (`core_username`.`site_id` = `core_site`.`id`)
ORDER BY `core_username`.`name` ASC LIMIT 1

这可能是什么原因?我不知道如何修复临时表,但我认为问题不在于它,因为每次都是新的临时表。用户名表相当大(现在有233,718条记录),但我不认为这与问题有任何关系。

非常感谢任何帮助。

更新:经过进一步测试,似乎只有在尝试对结果进行排序时才会出现错误。也就是说,这个查询会给我我期望的结果:

SELECT * FROM `core_username`
INNER JOIN `core_person` ON (`core_username`.`person_id` = `core_person`.`id`)
INNER JOIN `core_site` ON (`core_username`.`site_id` = `core_site`.`id`)
LIMIT 1

但如果我添加:

ORDER BY `core_username`.`name` ASC

出现了错误。这只发生在我当前使用的特定 Web 服务器上。如果我下载数据库并在我的本地主机以及其他服务器上尝试相同的操作,它就可以正常运行。MySQL 版本是 5.0.77。

基于这个情况,我相当有信心所发生的事情是正在创建的 tmp 表太大了,而 MySQL 则会出问题,如此博客文章所述。然而,我仍然不确定解决方案是什么......


5
@Paolo - 你在 /tmp 目录下有足够的空间吗? - martin clayton
1
@Paolo - 值得检查一下...虽然我没有更多的想法,但是MySQL的版本是什么? - martin clayton
有趣的阅读:http://forums.mysql.com/read.php?21,297810,297812#msg-297812 - OMG Ponies
1
这个查询语句是否会产生相同的错误:SELECT * FROM CORE_USERNAME u JOIN CORE_PERSON p ON p.id = u.person_id JOIN CORE_SITE s ON s.id = u.site_id WHERE u.name = (SELECT MIN(u.name) FROM CORE_USERNAME u) - OMG Ponies
@Paolo,你尝试过删除并重新添加core_username.name索引吗? - AJ.
显示剩余6条评论
11个回答

107
有时候,当临时表出现此错误时:
#126 - Incorrect key file for table '/tmp/#sql_64d_0.MYI'; try to repair it

可能是因为 /tmp 文件夹的空间不足。在某些 Linux 安装中,/tmp 位于自己的分区中并且没有太多的空间 - 大型 MySQL 查询将填满它。

您可以使用 df -h 命令检查 /tmp 是否位于自己的分区中,以及为其分配了多少空间。

如果它在自己的分区中并且空间不足,您可以选择:

(a) 修改 /tmp,使其分区拥有更多的空间(可以通过重新分配或将其移动到主分区来实现 - 例如,请参见这里
(b) 更改 MySql 的配置,使其在不同的分区上使用不同的临时文件夹,例如 /var/tmp


1
我的 df -h 结果如下: 文件系统 容量 已用 可用 使用% 挂载点 /dev/sda 2.0G 1.3G 646M 67% / udev 490M 4.0K 490M 1% /dev tmpfs 200M 232K 199M 1% /run none 5.0M 0 5.0M 0% /run/lock none 498M 0 498M 0% /run/shm overflow 1.0M 0 1.0M 0% /tmp因此我不确定这是否意味着 /tmp 在 1MB 溢出之内。无论如何,将 my.cnf 更改为使用 /var/tmp 作为文件夹解决了我的问题。MySQL 或 Ubuntu 能否很好地处理清理,因为我在当前服务器上遇到了磁盘空间问题? - M1ke
我只需要清理主分区上的硬盘空间,这个错误就消失了。谢谢你们的提示。 - fregas
你可以在运行脚本时使用 while true; do df -h /tmp; sleep 3; done 命令来查看临时表所占用的空间。 - biniam

22

在处理大型表时,运行查询时请检查你的MySQL tmpdir可用空间(/tmp为你的情况)。像这样的东西对我有用:

$ while true; do df -h /tmp; sleep .5; done

5
谢谢,这就是我遇到的问题。你也可以运行 watch -n0.5 df -h /tmp - Sam
1
这个方法很管用 - 观察到一个饥饿的查询吞噬了几个大型数据块。 - Laizer
1
是的,磁盘空间不足是导致此错误消息的原因。 - malhal

6

运行这个

REPAIR TABLE `core_username`,`core_site`,`core_person`;

或者这样做:
select * from (
 SELECT * FROM `core_username`
 INNER JOIN `core_person` ON (`core_username`.`person_id` = `core_person`.`id`)
 INNER JOIN `core_site` ON (`core_username`.`site_id` = `core_site`.`id`)
 LIMIT 1)
ORDER BY `name` ASC

1
这在临时表上不起作用(这就是OP遇到问题的地方)。 - Mark E. Haase

5

您可能会发现运行 "ANALYZE TABLE " 有所帮助。

我们在一个大表格(约100M行)上突然遇到了这个问题,MySQL尝试使用 /tmp 写入一个超过1GB的临时表,但由于 /tmp 限制为约600M,因此失败了。

事实证明,InnoDB表的统计信息相当陈旧。运行 "ANALYZE TABLE ..." 后,统计信息得到更新,问题得以解决。通过更准确的统计信息,MySQL能够正确优化查询,不再需要大型临时文件。

我们现在定期运行 "mysqlcheck -Aa" 来保持所有表格的统计信息新鲜。


3

我在一个拥有50万多条记录的表上遇到了一个查询问题。它一直给我同样类型的错误,指向/tmp目录中的.MYI文件,但检查时很少出现。我已经在/etc/my.cnf文件中增加了堆大小和临时文件大小。

查询问题的原因是它确实包含了一个ORDER从句,在末尾省略它使查询可以无错误运行。它还有一个LIMIT。我试图查看表中最近的5条记录。如果包含ORDER从句,它就会卡住并给出错误。

发生的情况是mysqld创建了一个内部临时表,将巨大表中所有记录都用来应用ORDER操作。

我解决这个问题的方法是应用额外的WHERE条件,将来自巨大表的记录限制为一些较小的集合。我方便地有一个日期时间字段进行过滤。

希望这可以帮助到某些人。


2
在Unix系统上,MySQL使用TMPDIR环境变量的值作为存储临时文件的目录路径。如果未设置TMPDIR,则MySQL使用系统默认值,通常为/tmp、/var/tmp或/usr/tmp。
在Windows、Netware和OS2上,MySQL按顺序检查TMPDIR、TEMP和TMP环境变量的值。对于第一个被设置的变量,MySQL使用它并不再检查其余的变量。如果没有设置TMPDIR、TEMP或TMP,则MySQL使用Windows系统默认值,通常为C:\windows\temp。
如果包含临时文件目录的文件系统太小,您可以使用mysqld的--tmpdir选项指定一个文件系统中具有足够空间的目录。
在MySQL 5.0中,--tmpdir选项可以设置为多个路径列表,这些路径会轮流使用。在Unix上应该用冒号字符(“:”)分隔路径,在Windows、NetWare和OS/2上应该用分号字符(“;”)分隔路径。

1

1

我遇到了同样的问题。

这是我的解决方案: 1. 不要使用 "select *"。只选择你需要的字段。 2. 分割查询。如果你选择的字段太多,将其分割成一些查询可能会有结果。如果你想要包含结果的变量不改变,可以稍后使用 "array_merge()" 合并结果。

在我的情况下,我将查询分成了 5 个查询,然后使用 PHP 进行了数组合并。

问题出在 mysql 服务器上。这只是应用程序开发人员(例如我)没有特权的事情。


0

我曾经遇到过类似的问题。在我的情况下,这个问题是由于错误的所有者/权限引起的。我只需要将数据目录的所有者更改为mysql用户,就解决了这个问题。


-1

其中3张表的索引键可能有问题,请尝试对所有3张表运行修复命令。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接