请参见下面的编辑#2,以获得最佳示例
原始问题如下,但并不能很好地代表我所问的内容。
假设我有两个表,每个表有4列:
- key(int,自动增量) - c1(日期) - c2(长度为3的varchar) - c3(也是长度为3的varchar)
并且我想执行以下查询:
SELECT t.c1, t.c2, COUNT(*)
FROM test1 t
LEFT JOIN test2 t2 ON t2.key = t.key
GROUP BY t.c1, t.c2
两个key
字段都作为主键进行索引。我想要得到每个c1、c2分组返回的行数。
当我解释这个查询时,会出现“using temporary; using filesort”的提示。实际上,我执行此查询的表格超过500,000行,这意味着这是一个耗时的查询。
所以我的问题是(假设在查询中没有做错任何事情):是否有一种方法可以对这个表进行索引,以消除临时/文件排序的使用?
非常感谢您提供的任何帮助。
编辑
以下是表格定义(在此示例中,两个表格相同 - 实际上它们不同,但我不确定这在这一点上是否有区别):
CREATE TABLE `test1` (
`key` int(11) NOT NULL auto_increment,
`c1` date NOT NULL,
`c2` varchar(3) NOT NULL,
`c3` varchar(3) NOT NULL,
PRIMARY KEY (`key`),
UNIQUE KEY `c1` (`c1`,`c2`),
UNIQUE KEY `c2_2` (`c2`,`c1`),
KEY `c2` (`c2`,`c3`)
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
完整的EXPLAIN语句:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t ALL NULL NULL NULL NULL 2 Using temporary; Using filesort
1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 tracking.t.key 1 Using index
这只是我的示例表格。在我的真实表格中,对于 t 的行,可能会显示 500,000+(尽管可能与其他事情有关)。
编辑#2
这里有一个更具体的例子,以更好地解释我的情况。
假设我有有关小联盟棒球比赛的数据。我有两个表格。一个包含比赛数据:
CREATE TABLE `ex_games` (
`game_id` int(11) NOT NULL auto_increment,
`home_team` int(11) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`game_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
另一个包含每场比赛中打击数据的数据集:
CREATE TABLE `ex_atbats` (
`ab_id` int(11) NOT NULL auto_increment,
`game` int(11) NOT NULL,
`team` int(11) NOT NULL,
`player` int(11) NOT NULL,
`result` tinyint(1) NOT NULL,
PRIMARY KEY (`hit_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
我有两个问题。让我们从简单的开始:我想返回一个游戏列表,并计算每个游戏中的打数。所以我认为我会做这样的事情:
SELECT date, home_team, COUNT(h.ab_id) FROM `ex_atbats` h
LEFT JOIN ex_games g ON g.game_id = h.game
GROUP BY g.game_id
这个查询使用了文件排序/临时表。有没有更好的方法来构建它或者为表格建立索引以消除这种情况?
然后,更棘手的部分:假设我现在不仅想包括击球数的计数,还要包括由同一队伍的相同结果的上一个击球之前的击球数的计数。我认为这会是类似于:
SELECT g.date, g.home_team, COUNT(ab.ab_id), COUNT(ab2.ab_id) FROM `ex_atbats` ab
LEFT JOIN ex_games g ON g.game_id = ab.game
LEFT JOIN ex_atbats ab2 ON ab2.ab_id = ab.ab_id - 1 AND ab2.result = ab.result
GROUP BY g.game_id
这是构造查询的正确方法吗?这也使用了文件排序/临时表。
那么,完成这些任务的最佳方式是什么?
再次感谢。
SELECT t.c1, t.c2, count(*)
代替? - Doug Kressexplain
命令在key
和key_len
列中显示了什么?请给我们展示完整的表定义。 - sanmai