3

I migrated all MySQL tables of one project from MyISAM to InnoDB last week, in order to support transaction. I used the command of alter table for this.

Most works fine, however one particular query runs very very slow, and it always gives the error Incorrect key file for table '/tmp/#sql_xxxx_x.MYI

Later I narrowed down the problem into the inner join of 2 tables, the user table and agreement table. And the inner join took place between the foreign key field of user (i.e. agreement_id) and primary key field of agreement (i.e. id).

The user table has only 50,000 rows of data, and the agreement table has, well, one single row. And we have set up the index for the agreement_id of user.

In any case, this seems to be a very light-weighted query, but it turns out to be the whole bottle neck.

Here is the full schema of agreement:

CREATE TABLE IF NOT EXISTS `agreement` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `remark` varchar(200) NOT NULL,
  `content` longtext NOT NULL,
  `is_active` tinyint(1) NOT NULL,
  `date_stamp` datetime NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

One thing I doubt about is the longtext field of remark inside the agreement table, but we did NOT use the field for the inner join, in fact the query is slow even if we did NOT select remark in the query result.

finally, we converted the table of agreement from innoDB back to MyISAM, than everything becomes normal. And the query is finished in less than 1 second.

Now, my question is what actually is going on here? Does that mean once an innoDB table contains any text field, then the table could not be used for inner join?

I wish I could know the real reason so that I could avoid the same problems in the future.

thanks a lot.

4

4 回答 4

2

这是一个著名而棘手的问题。最可能的原因是 /tmp 中的空间不足。

这是我保存在书签中的一个链接,可能会对您有所帮助:http ://www.mysqlperformancetuning.com/a-fix-for-incorrect-key-file-for-table-mysql

根据我的经验,虽然它是有限的,但看到此错误消息的主要原因是您的 tmpdir 空间不足。像我一样,你会检查你有多少可用空间:1Gb、2Gb、4Gb。这可能还不够。原因如下:MySQL 可以在几秒钟内创建比这更大的临时表,快速填满任何可用空间。自然取决于查询的性质和数据库的大小。

你也可以在你的桌子上尝试修复,但对我来说它和霹雳舞一样有用:/

于 2012-06-20T11:53:02.403 回答
1

也许这里的问题是remark字段定义为varchar(200)?请记住,临时表和内存表varchar以固定长度存储。varchar(200)因此,即使它们都是空的,50k 行也会消耗大量内存。

如果这是问题所在,那么您可以尝试以下几种方法之一:

于 2012-06-25T17:05:27.860 回答
1

您查询的目的是什么?我从您的评论中看到,您只列出了用户信息,而没有任何协议让我相信您正在寻找有协议的用户?由于您在引擎之间进行转换,因此我认为您在添加约束之前正在进行清理。如果是这样,请考虑来自用户表的左连接,而不是像:

select user.* from user left join agreement on user.agreement_id = agreement.id where user.agreement_id != 0;

如果它不是清理,而只是寻找有协议的用户,我们让它变得简单

select user.* from user where user.agreement_id != 0;

如果目的是别的,考虑在 user.agreement_id 上添加一个索引,因为内部连接可能需要它来提高速度。让我们知道真正的目的,您可能会得到更好的帮助。

于 2012-06-26T14:36:37.013 回答
1

InnoDB 有自己的缓冲区大小设置等。检查一下,如果你可以调整它,继续。只是为了测试尝试将它们加倍,如果有帮助,您可能需要优化它。它可以产生很大的不同。

一些可能有帮助的链接:

http://www.mysqlperformanceblog.com/2007/11/03/choosing-innodb_buffer_pool_size/

http://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html

于 2012-06-25T15:40:38.800 回答