atl*_*lau 7 mysql optimization
所以我有一个512mb内存的vps,以及一个像这样的MySQL表:
CREATE TABLE `table1` (
`id` int(20) unsigned NOT NULL auto_increment,
`ts` timestamp NOT NULL default CURRENT_TIMESTAMP,
`value1` char(31) collate utf8_unicode_ci default NULL,
`value2` varchar(100) collate utf8_unicode_ci default NULL,
`value3` varchar(100) collate utf8_unicode_ci default NULL,
`value4` mediumtext collate utf8_unicode_ci,
`type` varchar(30) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`),
KEY `date` (`ts`)
) ENGINE=MyISAM AUTO_INCREMENT=469692 DEFAULT CHARSET=utf8
COLLATE=utf8_unicode_ci
Run Code Online (Sandbox Code Playgroud)
如果我执行这样的查询,则需要2~18秒才能完成:
SELECT `id`, `ts`, `value1`, `value2`, `value3` FROM table1 WHERE
`type` = 'something' ORDER BY `id` DESC limit 0,10;
Run Code Online (Sandbox Code Playgroud)
EXPLAIN SELECT告诉我:
select_type: SIMPLE
type: ref
possible_keys: type
key: type
key_len: 92
ref: const
rows: 7291
Extra: Using where; Using filesort
Run Code Online (Sandbox Code Playgroud)
我认为'使用filesort'可能是问题,但结果并非如此.如果我删除ORDER BY和LIMIT,查询速度是相同的(我关闭查询缓存以进行测试
SET @@query_cache_type=0;).
mysql> EXPLAIN SELECT `id`,`ts`,`value1`,`value2`, `value3`
FROM table1 WHERE `type` = 'something'\G
select_type: SIMPLE
type: ref
possible_keys: type
key: type
key_len: 92
ref: const
rows: 7291
Extra: Using where
Run Code Online (Sandbox Code Playgroud)
不知道它是否重要但行近似是不准确的:
SELECT COUNT(*) FROM table1 WHERE `type` = 'something';
Run Code Online (Sandbox Code Playgroud)
返回22.8k行.
查询似乎已经优化,我不知道如何进一步改进它.整个表包含370k行,大小约为4.6 GiB.是否有可能因为类型是逐行随机变化(随机分布在整个表中),从磁盘获取数据需要2~18秒?
有趣的是,当我使用只有几百行的类型时,这些查询也很慢.MySQL以大约100行/秒的速度返回行!
|-------+------+-----------|
| count | time | row/sec |
|-------+------+-----------|
| 22802 | 18.7 | 1219.3583 |
| 11 | 0.1 | 110. |
| 491 | 4.8 | 102.29167 |
| 705 | 5.6 | 125.89286 |
| 317 | 2.6 | 121.92308 |
|-------+------+-----------|
Run Code Online (Sandbox Code Playgroud)
为什么这么慢?我可以进一步优化查询吗?我应该将数据移动到较小的表吗?
我认为自动分区是一个好主意,为每个类型动态创建一个新分区.这是不可能的,原因很多,包括最大分区数是1024,并且可以有任何类型.我还可以尝试应用程序级别分区,为每种新类型创建一个新表.我不想这样做,因为它引入了极大的复杂性.我不知道如何为所有表中的所有行设置唯一ID.此外,如果我达到多次插入/秒,性能将显着下降.
提前致谢.
您需要该查询的多列索引:
KEY `typeid` (`type`, `id`)
Run Code Online (Sandbox Code Playgroud)
不幸的是,正如您所说,如果没有 ORDER,它也很慢,所以它很慢,因为记录分散在磁盘上,并且必须进行大量查找。一旦缓存,它应该很快(注意:22.8/370 * 4.6G = 283M,所以如果您执行其他活动/查询,这些记录不会在内存中停留很长时间,甚至可能不适合。)。
执行此操作iostat 1来验证 I/O 瓶颈。大量 RAM 可以解决您的问题。SSD 也可以解决您的问题。但内存更便宜;)