计算每个ID的unix时间戳之间的行数

时间:2012-09-07 05:17:41

标签: mysql performance

我正在尝试为表格填充一些数据。该查询正在包含约5000万条记录的表上运行。我目前使用的查询如下。它计算与template id匹配的行数,并且BETWEEN两个unix时间戳:

SELECT COUNT(*) as count FROM `s_log` 
WHERE `time_sent` BETWEEN '1346904000' AND '1346993271' 
AND `template` = '1'

虽然上面的查询确实有效,但在循环遍历每个template时性能相当慢,有时可能是数百个。时间戳存储为int并正确编入索引。只是为了测试一下,我尝试运行下面的查询,省略time_sent限制:

SELECT COUNT(*) as count FROM `s_log` 
AND `template` = '1'

正如预期的那样,它运行得非常快,但显然不会在正确的时间范围内限制计数结果。如何获取特定template的计数并限制该计数BETWEEN两个unix时间戳?

EXPLAIN:

1 |简单| s_log | ref | time_sent,模板|模板| 4 | const | 71925 |使用何处

SHOW CREATE TABLE s_log:

CREATE TABLE `s_log` (
 `id` int(255) NOT NULL AUTO_INCREMENT,
 `email` varchar(255) NOT NULL,
 `time_sent` int(25) NOT NULL,
 `template` int(55) NOT NULL,
 `key` varchar(255) NOT NULL,
 `node_id` int(55) NOT NULL,
 `status` varchar(55) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `email` (`email`),
 KEY `time_sent` (`time_sent`),
 KEY `template` (`template`),
 KEY `node_id` (`node_id`),
 KEY `key` (`key`),
 KEY `status` (`status`),
 KEY `timestamp` (`timestamp`)
) ENGINE=MyISAM AUTO_INCREMENT=2078966 DEFAULT CHARSET=latin1

3 个答案:

答案 0 :(得分:1)

在这种情况下,您可能拥有的最佳索引是复合索引template + time_sent

CREATE INDEX template_time_sent ON s_log (template, time_sent)

PS:同样只要查询中的所有列都是整数 DO NOT 将它们的值括在引号中(在某些情况下,它可能会导致问题,至少在较旧的mysql版本中)< / p>

答案 1 :(得分:0)

首先,您必须创建一个将两个列放在一起的索引(不是单独的)。还要检查你的表类型,我认为如果你的表是innoDB,它会很好用。

最后,以这种方式使用WHERE子句:

`WHERE模板= '1' AND time_sent` BETWEEN'1346904000'和'1346993271'

这样做首先检查模板是否为1,如果是,那么它将检查第二个条件否则跳过。这肯定会给你性能优势

答案 2 :(得分:0)

如果您必须为每个模板调用查询,那么使用GROUP BY通过一次查询调用获取所有信息会更快:

SELECT template, COUNT(*) as count FROM `s_log` 
WHERE `time_sent` BETWEEN 1346904000 AND 1346993271;
GROUP BY template

只是猜测这会更快,你也需要重新设计你的代码。

<小时/> 您也可以尝试使用InnoDB代替MyISAMInnoDB使用聚簇索引,该索引可能在大型表上执行得更好。来自MySQL网站:

  

通过聚簇索引访问行很快,因为行数据位于索引搜索所在的同一页面上。如果表很大,与使用与索引记录不同的页面存储行数据的存储组织相比,聚簇索引体系结构通常会保存磁盘I / O操作。 (例如,MyISAM使用一个文件用于数据行,另一个文件用于索引记录。)

Stackoverflow上有一些问题讨论InnoDBMyISAM之间的效果: