【发布时间】:2012-03-19 16:02:15
【问题描述】:
我有一个大约有 120k 行的表,其中包含一个带有 BLOB 的字段(每个条目的大小不超过 1MB,通常要小得多)。我的问题是,每当我运行查询该表上的任何列(不 包括 BLOB 列)时,如果文件系统缓存为空,则大约需要 40 英寸才能完成。同一张表上的所有后续查询都需要小于 1'' (从命令行客户端测试,在服务器本身上)。查询中返回的行数从空集到 60k+ 不等
我已经消除了查询缓存,所以它与它无关。 该表是 myisam,但我也尝试将其更改为 innodb(并设置 ROW_FORMAT=COMPACT),但没有任何运气。
如果我删除 BLOB 列,查询总是很快。
所以我假设服务器从磁盘(或其中的一部分)读取 blob,并且文件系统缓存它们。问题在于,在流量高且内存有限的服务器上,文件系统缓存每隔一段时间就会刷新一次,所以这个特定的查询一直给我带来麻烦。
所以我的问题是,有没有一种方法可以大大加快速度,而无需从表中删除 blob 列?
这里有 2 个示例查询,一个接一个地运行,以及解释、索引和表定义:
mysql> SELECT ct.score FROM completed_tests ct where ct.status != 'deleted' and ct.status != 'failed' and score < 100;
Empty set (48.21 sec)
mysql> SELECT ct.score FROM completed_tests ct where ct.status != 'deleted' and ct.status != 'failed' and score < 99;
Empty set (1.16 sec)
mysql> explain SELECT ct.score FROM completed_tests ct where ct.status != 'deleted' and ct.status != 'failed' and score < 99;
+----+-------------+-------+-------+---------------+--------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------+---------+------+-------+-------------+
| 1 | SIMPLE | ct | range | status,score | status | 768 | NULL | 82096 | Using where |
+----+-------------+-------+-------+---------------+--------+---------+------+-------+-------------+
1 row in set (0.00 sec)
mysql> show indexes from completed_tests;
+-----------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-----------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| completed_tests | 0 | PRIMARY | 1 | id | A | 583938 | NULL | NULL | | BTREE | |
| completed_tests | 1 | users_login | 1 | users_LOGIN | A | 11449 | NULL | NULL | YES | BTREE | |
| completed_tests | 1 | tests_ID | 1 | tests_ID | A | 140 | NULL | NULL | | BTREE | |
| completed_tests | 1 | status | 1 | status | A | 3 | NULL | NULL | YES | BTREE | |
| completed_tests | 1 | timestamp | 1 | timestamp | A | 291969 | NULL | NULL | | BTREE | |
| completed_tests | 1 | archive | 1 | archive | A | 1 | NULL | NULL | | BTREE | |
| completed_tests | 1 | score | 1 | score | A | 783 | NULL | NULL | YES | BTREE | |
| completed_tests | 1 | pending | 1 | pending | A | 1 | NULL | NULL | | BTREE | |
+-----------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
mysql> show create table completed_tests;
+-----------------+--------------------------------------
| Table | Create Table |
+-----------------+--------------------------------------
| completed_tests | CREATE TABLE `completed_tests` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`users_LOGIN` varchar(100) DEFAULT NULL,
`tests_ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
`test` longblob,
`status` varchar(255) DEFAULT NULL,
`timestamp` int(10) unsigned NOT NULL DEFAULT '0',
`archive` tinyint(1) NOT NULL DEFAULT '0',
`time_start` int(10) unsigned DEFAULT NULL,
`time_end` int(10) unsigned DEFAULT NULL,
`time_spent` int(10) unsigned DEFAULT NULL,
`score` float DEFAULT NULL,
`pending` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `users_login` (`users_LOGIN`),
KEY `tests_ID` (`tests_ID`),
KEY `status` (`status`),
KEY `timestamp` (`timestamp`),
KEY `archive` (`archive`),
KEY `score` (`score`),
KEY `pending` (`pending`)
) ENGINE=InnoDB AUTO_INCREMENT=117996 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED
1 row in set (0.00 sec)
我最初在mysql query slow at first fast afterwards 上发布了这个,但我现在有更多信息,所以我重新发布为一个不同的问题 我也在mysql forum 上发布了这个,但我还没有收到回复
一如既往地提前感谢
【问题讨论】:
-
+1 写得很好,完整的问题。我希望你能得到一个好的答案(我什么都没有 :-) 如果你在 mysql 论坛上得到一个答案而没有人在这里回答,请发布答案(作为下面的答案),等待必要的 48 小时,然后接受它.您不会获得积分,但它会显示为其他搜索此主题的人的已回答问题。祝你好运。
-
无法回答“为什么”部分。我可以建议你不要关心这个。好的,你知道你的第一个查询很慢。所以呢?据我了解,任何后续查询都很快。所以知道构建你的应用程序知道这个事实。在某些时候添加“预热”阶段,例如当客户必须在登录表单中输入字符时。就像那样......这比玩缓存设置要好。
-
这不仅是第一个查询很慢,只要系统内存可用性低就会发生
-
哦 " 是分钟?我以为你在这里谈论秒...忽略我的 cmets。
标签: mysql performance caching blob