【发布时间】:2014-09-22 11:55:41
【问题描述】:
我正在使用 mySQL 5.6.13.2 并且有一个查询涉及父表中的 150,000 行,子表中的行超过 1M。如果我删除 GROUP BY(仅作为测试),查询需要 2 秒,如果我有 GROUP BY,则需要超过 6 秒,这是需要的。
我已阅读其他有关如何使用临时删除的帖子;使用文件排序,但这些并不能解决问题。我希望在这里得到一些帮助。
演示所有这些的 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,那么 EXPLAIN 会显示 Using where;使用没有临时或文件排序的索引,查询运行时间为 2 秒而不是 6 秒。
必须将这些结果按测试 ID 分组。此外,测试 ID 值是任意的,并且事先不知道,因此无法针对硬编码的已知测试 ID 编写带有子查询的查询。
是否可以定义其他可能停止临时和文件排序的索引?如果没有,是否有更有创意的方式来重写这个查询,这样会更有效并可能解决这个问题?
请注意,在 GROUP BY 之后,我的查询确实有一些 HAVING 和 ORDER BY 条件(特别是它去...... GROUP BY testid 有 Category1 OR Category2 OR Category3 order by Category1 desc, Category2 desc;” - 但是我忽略了这个这里的例子是因为我得到了相同的性能和 EXPLAIN 输出有或没有扩展子句,我想保持样本尽可能简单。我在这里提到它是因为如果你有一个创造性的方法来重写查询,如果你能请包括它会很好。
如前所述,这里有一个 SQL fiddle http://sqlfiddle.com/#!9/edeb6/1 演示了该问题(因此您可以查看 EXPLAIN 输出和实验)。
谢谢!
【问题讨论】:
-
必须是一条 SQL 语句吗?带有游标的存储过程是否可以选择?
-
感谢您的评论草本。是的,它必须是单个 SQL 语句(当然可能包含子查询)。
标签: mysql sql query-optimization database-performance sqlperformance