Mysql 为简单的频繁查询创建排序索引性能
Mysql Creating sort index performance for simple frequent query
我正在处理一个 mysql table 大约有 400 万条消息条目,我正在尝试 select 基于时间戳的最新 50 条消息。
附加要求是返回的消息不以固定前缀开头。
问题是单个查询大约需要 25% cpu,大约需要 1.5 秒。该查询经常由多个客户端执行,并导致我们的 8 核数据库服务器出现性能问题。
SELECT * FROM largeTable
WHERE msg NOT LIKE 'myPrefix%'
ORDER BY timestamp DESC LIMIT 0, 50;
我尝试使用内置 mysql 分析器进行分析,这是查询的结果:
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000044 |
| checking permissions | 0.000004 |
| Opening tables | 0.000010 |
| init | 0.000019 |
| System lock | 0.000005 |
| optimizing | 0.000005 |
| statistics | 0.000007 |
| preparing | 0.000007 |
| Sorting result | 0.000002 |
| executing | 0.000002 |
| Sending data | 0.000006 |
| Creating sort index | 0.788023 |
| end | 0.000009 |
| query end | 0.000003 |
| closing tables | 0.000009 |
| freeing items | 0.000012 |
| cleaning up | 0.000010 |
+----------------------+----------+
我首先想到可能问题在于它检查了所有条目的前缀,但是在分析之后。
| Creating sort index | 0.788023 |
似乎是罪魁祸首。那么 ORDER BY 子句呢?
我怎样才能加快速度?
我可以建立某种类型的索引来解决这个问题吗?
大约每隔几秒添加一次新消息,而查询发生的频率更高。
感谢您的帮助!
编辑:感谢您的评论,这是请求的信息。
数据库不是由我的代码创建和填充的,而是由某些外部 python 服务创建和填充的。我还没有添加任何索引。
解释输出:
id:1
select_type:SIMPLE
table:largeTable
type:ALL
possible_keys:NULL
key: NULL
key_len:NULL
ref: NULL
rows: 3492633
Extra: Using where; Using filesort
Table结构:
CREATE TABLE `largeTable` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`timestamp` int(10) unsigned NOT NULL,
`client_id` int(11) unsigned NOT NULL,
`name` varchar(32) NOT NULL,
`msg` varchar(528) NOT NULL,
`target_id` int(11) unsigned DEFAULT NULL,
`target_name` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `client` (`client_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4013829 DEFAULT CHARSET=utf8 |
EXPLAIN
和 CREATE TABLE
表示您没有用于优化 WHERE
子句的索引。这发生在 ORDER BY
之前。所以让我们先关注索引。
ALTER TABLE largeTable
ADD INDEX(msg);
但是,这行不通,原因有两点:
`msg` varchar(528) NOT NULL,
ENGINE=MyISAM
你需要528个字符吗?如果你可以将它降低到 255,那会起作用。 (或者对于 MyISAM 可能是 341。)
你 运行 MySQL 是什么版本? 5.7 允许 528+utf8 作为索引。 5.6也可以这样做,但你必须做一些步骤才能使它成为可能。
我正在处理一个 mysql table 大约有 400 万条消息条目,我正在尝试 select 基于时间戳的最新 50 条消息。
附加要求是返回的消息不以固定前缀开头。
问题是单个查询大约需要 25% cpu,大约需要 1.5 秒。该查询经常由多个客户端执行,并导致我们的 8 核数据库服务器出现性能问题。
SELECT * FROM largeTable
WHERE msg NOT LIKE 'myPrefix%'
ORDER BY timestamp DESC LIMIT 0, 50;
我尝试使用内置 mysql 分析器进行分析,这是查询的结果:
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000044 |
| checking permissions | 0.000004 |
| Opening tables | 0.000010 |
| init | 0.000019 |
| System lock | 0.000005 |
| optimizing | 0.000005 |
| statistics | 0.000007 |
| preparing | 0.000007 |
| Sorting result | 0.000002 |
| executing | 0.000002 |
| Sending data | 0.000006 |
| Creating sort index | 0.788023 |
| end | 0.000009 |
| query end | 0.000003 |
| closing tables | 0.000009 |
| freeing items | 0.000012 |
| cleaning up | 0.000010 |
+----------------------+----------+
我首先想到可能问题在于它检查了所有条目的前缀,但是在分析之后。
| Creating sort index | 0.788023 |
似乎是罪魁祸首。那么 ORDER BY 子句呢? 我怎样才能加快速度? 我可以建立某种类型的索引来解决这个问题吗? 大约每隔几秒添加一次新消息,而查询发生的频率更高。
感谢您的帮助!
编辑:感谢您的评论,这是请求的信息。
数据库不是由我的代码创建和填充的,而是由某些外部 python 服务创建和填充的。我还没有添加任何索引。
解释输出:
id:1
select_type:SIMPLE
table:largeTable
type:ALL
possible_keys:NULL
key: NULL
key_len:NULL
ref: NULL
rows: 3492633
Extra: Using where; Using filesort
Table结构:
CREATE TABLE `largeTable` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`timestamp` int(10) unsigned NOT NULL,
`client_id` int(11) unsigned NOT NULL,
`name` varchar(32) NOT NULL,
`msg` varchar(528) NOT NULL,
`target_id` int(11) unsigned DEFAULT NULL,
`target_name` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `client` (`client_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4013829 DEFAULT CHARSET=utf8 |
EXPLAIN
和 CREATE TABLE
表示您没有用于优化 WHERE
子句的索引。这发生在 ORDER BY
之前。所以让我们先关注索引。
ALTER TABLE largeTable
ADD INDEX(msg);
但是,这行不通,原因有两点:
`msg` varchar(528) NOT NULL,
ENGINE=MyISAM
你需要528个字符吗?如果你可以将它降低到 255,那会起作用。 (或者对于 MyISAM 可能是 341。)
你 运行 MySQL 是什么版本? 5.7 允许 528+utf8 作为索引。 5.6也可以这样做,但你必须做一些步骤才能使它成为可能。