【发布时间】:2013-02-16 06:28:51
【问题描述】:
我有一个 mysql 表,它可能包含数百万行数据——在某些极端情况下高达 1 亿行。我开发的一个应用程序经常查询这些数据,我已经尽我所能来优化它——在大多数情况下,它工作得非常快,因为我们只搜索数据的一个非常小的子集(与位置相关) .
表结构:
CREATE TABLE `prism_actions` (
`id` int(11) unsigned NOT NULL auto_increment,
`action_time` timestamp NOT NULL default CURRENT_TIMESTAMP,
`action_type` varchar(25) NOT NULL,
`player` varchar(16) NOT NULL,
`world` varchar(255) NOT NULL,
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
`z` int(11) NOT NULL,
`block_id` mediumint(5) unsigned NOT NULL,
`block_subid` mediumint(5) unsigned NOT NULL,
`data` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `x` (`x`),
KEY `action_type` (`action_type`),
KEY `player` (`player`),
KEY `block_id` (`block_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
对于我们在 WHERE 语句中最常使用的字段,我有几个基本索引,当用于只有一个条件的查询时 - 它非常快。
我正在运行这些测试的示例表有 2200 万条记录。
例子:
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.action_type = 'block-break' LIMIT 1000;
1000 rows in set (0.00 sec)
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (0.01 sec)
我的问题是,对于我们在查询中使用的每个条件(大多数查询通常有几个条件),查询需要更长的时间。
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.action_type = 'block-break' AND prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (0.79 sec)
0.79 秒对于完整查询是可以接受的,但这只是使用了部分条件。
真正的查询更像是:
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.action_type = 'block-break' AND prism_actions.player = 'viveleroi' AND prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (2.22 sec)
我们使用0.01 运行一个条件,使用0.79 运行两个条件,使用2.2 运行三个条件,这太长了。
我将研究如何更好地设计我的索引,但我对当前的数据库架构和索引非常满意。
但是,当这样一起使用时,我可以尝试什么来使条件更快?
更新
我花时间将表格转换为外键格式。 player、action_type 和 world 列数据被移动到单独的表中,并且它们的 ID 存储在原始表中。迁移数据花了几个小时。
但是,我正在重新运行我之前使用过的相同查询,虽然我看到一些查询速度有所提高,但我发现其他查询几乎没有变化。
上述 0.79 秒查询的转换版本运行速度大致相同:
SELECT prism_actions.id FROM prism_actions WHERE prism_actions.actiontype_id = 1 AND prism_actions.block_id = 2 LIMIT 1000;
1000 rows in set (0.73 sec)
block_id col 仍然有来自原始表模式的索引。
以 player_id 为条件的查询运行非常缓慢,因此我在列中添加了一个索引,现在查询速度非常快。
但是,在以真实用户的几个查询示例并针对此表结构更新它们之后,我发现速度没有变化。
SELECT prism_actions.id FROM prism_actions WHERE (prism_actions.actiontype_id = 2 OR prism_actions.actiontype_id = 1) AND (prism_actions.player_id = 1127) AND prism_actions.action_time >= '2013-02-22 07:47:54' LIMIT 1000;
以前拍5.83 sec,现在拍5.29 sec
编辑 - 似乎是时间戳。从上面的查询中取出时间戳条件会在 0.01 秒内返回结果。为时间戳添加索引没有任何作用 - 想法?
到目前为止,我真正看到的只是某些区域的速度略有提高,因为我们存储了重复的字符串而节省了少量文件空间 - 但到目前为止,还没有什么值得让数百名拥有如此大数据库的用户花费花一天时间转换数据。
对我可能索引内容等的其他方式有什么建议吗?
【问题讨论】:
-
如果引擎是innodb是什么情况?他们慢吗?
-
在文本列上搜索将不可避免地比在 int 列上搜索慢得多,这就是为什么在 where 子句中包含这些时间会大大增加。
-
@PradyutBhattacharya MyISAM 建议用于只读表。 InnoDB 会更慢。
-
你可以使用分区吗?
-
你的 MySQL 版本是多少?
标签: mysql performance query-optimization