代码之家  ›  专栏  ›  技术社区  ›  Paolo Bergantino

进行多个联接时,mysql tmp表的密钥文件不正确

  •  57
  • Paolo Bergantino  · 技术社区  · 14 年前

    我不经常来这里寻求帮助,但我对此感到非常沮丧,我希望有人以前遇到过这种情况。

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

    #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
    

    是什么导致的?我真的不知道如何去修复一个tmp表,但我不认为这是问题所在,因为它每次都是一个新的tmp表。用户名表相当大(目前有233718条记录),但我怀疑这与它有什么关系。

    任何帮助都将不胜感激。

    更新 :经过进一步测试后,似乎只有在我尝试订购结果时才会出现错误。也就是说,这个查询将提供我所期望的:

    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也会窒息。 as described in this blog post . 不过,我仍然不确定解决办法是什么…

    11 回复  |  直到 8 年前
        1
  •  101
  •   codeulike    14 年前

    有时,当临时表发生此错误时:

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

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

    你可以用 df -h 检查是否 \tmp 在它自己的分区中,以及分配给它的空间大小。

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

    (a)修改/tmp,使其分区有更多的空间(通过重新分配或移动到主分区-例如 see here )
    (B)更改mysql配置,以便使用 different temp folder 在不同的分区上,例如 /var/tmp

        2
  •  20
  •   Francesc Rosàs    14 年前

    在运行查询时检查您的mysql tmpdir可用空间(/tmp,在您的情况下),因为使用大表时,它可能会占用数百MB。这对我很有用:

    $ while true; do df -h /tmp; sleep .5; done
    
        3
  •  6
  •   Pentium10    14 年前

    运行此

    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
    
        4
  •  4
  •   Community Egal    10 年前

    您可能会发现运行“分析表”有帮助。

    我们突然在一个大表上出现了这个问题(~100M行),mysql试图用/tmp来写一个超过1GB的临时表,但失败了,因为/tmp限制在~600M。

    结果发现innodb表的统计数据相当陈旧。运行“分析表…”后,更新统计信息并清除问题。通过更准确的统计,MySQL能够正确地优化查询,不再需要大的tmp文件。

    我们现在定期运行“mysqlcheck-aa”,以保持所有表统计信息的新鲜性。

        5
  •  3
  •   ClickWhisperer    10 年前

    我对一个有500K以上记录的表进行查询时遇到了这个问题。 它给了我同样类型的错误,指向/tmp目录中的一个.myi文件,这个文件在检查时很少出现。我已经在/etc/my.cnf文件中增加了堆和临时文件的大小。

    查询的问题是它在结尾处确实包含了一个ORDER子句,省略了它使查询工作无误。它也有一个限制。我正试图查看表中最近的5个记录。其中包含了ORDER子句,它被阻塞并给出了错误。

    发生的是mysqld创建了一个内部临时表,其中包含了巨表中的所有记录以应用该命令。

    我解决这个问题的方法是应用一个额外的Where条件,将记录从大表限制到较小的集合。我很方便地有一个日期时间字段来进行筛选。

    我希望这能帮助别人。

        6
  •  2
  •   Jaydeep Dave    12 年前

    在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。

    如果包含临时文件目录的文件系统太小, 您可以使用--tmpdir选项mysqld来指定文件系统中有足够空间的目录。 .

    在MySQL5.0中,可以将--tmpdir选项设置为以循环方式使用的多个路径的列表。在UNIX上,路径应使用冒号字符(_:_)分隔,在Windows、Netware和OS/2上,路径应使用分号字符(___)分隔。

        7
  •  1
  •   Ahmad    12 年前

    我也遇到同样的问题。

    这是我的解决方案: 1。不要使用“选择*”。只需选择您需要的字段。 2。拆分查询。如果选择的字段太多,则可能导致将其拆分为某些查询。如果不想更改包含结果的变量,可以稍后对结果“array_merge()”。

    在我的示例中,我将查询拆分为5个查询,然后使用PHP对其进行数组合并。

    问题出在MySQL服务器上。这只是一件应用程序开发人员(比如我们)没有先例的事情。

        8
  •  0
  •   Lateef    10 年前

    我也有类似的问题。在我自己的情况下,问题是由于不正确的所有者/权限而发生的。我只需要将数据目录的所有者更改为mysql用户,这就解决了问题。

        10
  •  -1
  •   Gabriel Solomon    14 年前

    三个表中的一个的索引键可能不正确,请尝试对所有三个表运行修复命令。

        11
  •  -1
  •   Jon    14 年前

    使用explain关键字可能有助于了解如何最好地优化此查询。本质上,您需要做的是尽可能快地得到尽可能小的结果集。如果您在core-username中的每一行都有一个结果集,直到最后,当您订购它时,您将面临以下风险…这个。

    如果您可以单独对core_用户名进行排序,而不会出现任何问题,那么您可能需要将min()行作为子查询。