我有一个 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 秒内返回结果。为时间戳添加索引什么都不做 - 想法?
到目前为止,我真正看到的只是某些区域的速度略有提高,由于我们存储了重复的字符串,因此节省了少量文件空间——但到目前为止,还没有什么值得让拥有这么大数据库的数百名用户花费一天的时间时间转换数据。
对我可能索引东西等的其他方式有什么建议吗?