如何改进已经优化的查询需要18秒?

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.此外,如果我达到多次插入/秒,性能将显着下降.

提前致谢.

Kar*_*ath 4

您需要该查询的多列索引:

KEY `typeid` (`type`, `id`)
Run Code Online (Sandbox Code Playgroud)

不幸的是,正如您所说,如果没有 ORDER,它也很慢,所以它很慢,因为记录分散在磁盘上,并且必须进行大量查找。一旦缓存,它应该很快(注意:22.8/370 * 4.6G = 283M,所以如果您执行其他活动/查询,这些记录不会在内存中停留很长时间,甚至可能不适合。)。

执行此操作iostat 1来验证 I/O 瓶颈。大量 RAM 可以解决您的问题。SSD 也可以解决您的问题。但内存更便宜;)