我正在使用mySQL 5.6.13.2,并且在父表中有一个涉及150,000行的查询,子表中包含超过1M行。如果我删除GROUP BY(仅作为测试),则查询需要2秒;如果我有GROUP BY,则查询需要6秒钟。
我已经阅读了有关如何使用临时删除的其他帖子;使用filesort但这些都没有解决问题。我希望能得到一些帮助。
可以在这里找到演示所有这些内容的SQL小提琴:http://sqlfiddle.com/#!9/edeb6/1
CREATE TABLE `summary` (
`RunID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`LastUpdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`FileName` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`XCount` int(11) DEFAULT NULL,
`YCount` int(11) DEFAULT NULL,
`AccountID` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`RunID`),
KEY `acct-lastupdate` (`AccountID`,`LastUpdate`),
KEY `acct-lastupdate-counts` (`AccountID`,`LastUpdate`,`XCount`,`YCount`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `detail` (
`DetailID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`LastUpdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`RunID` int(10) unsigned DEFAULT NULL,
`TestID` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL,
`ResultCode` int(11) DEFAULT NULL,
PRIMARY KEY (`DetailID`),
KEY `detail_runid` (`RunID`),
KEY `detail_testid` (`TestID`),
KEY `detail_runid_testid_result` (`RunID`,`TestID`,`ResultCode`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
以下是我的查询的EXPLAIN输出:
EXPLAIN select
testid as 'TestID',
sum(case when resultcode = 1 then 1 else 0 end) as Category1,
sum(case when resultcode = 2 then 1 else 0 end) as Category2,
sum(case when resultcode = 0 then 1 else 0 end) as Category3
from detail d, summary s
where s.accountid = 'xyz'
and s.lastupdate >= '2014-05-26 00:00:00'
and s.lastupdate < '2014-07-27 00:00:00'
and s.runid = d.runid
and s.runid <= 9999999999
GROUP BY testid;
1 SIMPLE s ref PRIMARY,acct-lastupdate,acct-lastupdate-counts acct-lastupdate 78 const 2 Using where; Using index; Using temporary; Using filesort
1 SIMPLE d ref detail_runid,detail_runid_testid_result detail_runid 5 db_9_edeb6.s.RunID 1 (null)
如果我删除了GROUP BY,则说明使用where;使用没有临时或文件排序的索引,查询在2秒而不是6秒内运行。
将这些结果按测试ID分组是必需的。此外,测试ID值是任意的,并且事先不知道,因此无法使用子查询编写带有硬编码的已知测试ID的查询。
是否可以定义可能会停止临时和文件排序的其他索引?如果没有,是否有更有创意的方法来重写这个更高效的查询,并可能解决这个问题?
请注意,在GROUP BY我的查询之后确实有一些HAVING和ORDER BY条件(特别是它...... GROUP BY testid具有Category1或Category2或Category3 order by Category1 desc,Category2 desc;“ - 但是我把它留了出来这里的例子是因为我得到了相同的性能和EXPLAIN输出,有或没有扩展的子句,我想让样本尽可能简单。我在这里提到它,因为如果你有创造性的方法来重写查询,如果你能请包括它会很好。
如上所述,这里有一个SQL小提琴http://sqlfiddle.com/#!9/edeb6/1来演示这个问题(所以你可以看到EXPLAIN输出和实验)。
谢谢!
答案 0 :(得分:0)
如果是一个选项,则尝试将“accountid”字段添加到“detail”表中。然后,您不需要加入此查询的摘要表。从查询中删除“摘要”表,并将“s”别名指向“d”。然后EXPLAIN只显示使用where。但我不知道它是否比你的快得多。
语句“sum(结果代码= 1然后1其他0结束时的情况)”你可以像这样写“sum(resultcode = 1)作为Category1,sum(reusltcode = 2)作为Category2 ......”< / p>