这感觉就像是为我做的功课"有点问题,但我真的卡在这里试图使这个查询快速运行对很多行的表。显示架构的Here's a SQLFiddle(或多或少)。
我已经使用了索引,试图获得能显示所有必需列的内容,但却没有取得多大成功。这是create
:
CREATE TABLE `AuditEvent` (
`auditEventId` bigint(20) NOT NULL AUTO_INCREMENT,
`eventTime` datetime NOT NULL,
`target1Id` int(11) DEFAULT NULL,
`target1Name` varchar(100) DEFAULT NULL,
`target2Id` int(11) DEFAULT NULL,
`target2Name` varchar(100) DEFAULT NULL,
`clientId` int(11) NOT NULL DEFAULT '1',
`type` int(11) not null,
PRIMARY KEY (`auditEventId`),
KEY `Transactions` (`clientId`,`eventTime`,`target1Id`,`type`),
KEY `TransactionsJoin` (`auditEventId`, `clientId`,`eventTime`,`target1Id`,`type`)
)
select
的一个版本:
select ae.target1Id, ae.type, count(*)
from AuditEvent ae
where ae.clientId=4
and (ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00')
group by ae.target1Id, ae.type;
我最终得到了一个'使用临时'和'使用filesort'同样。我尝试删除count(*)
并使用select distinct
代替,但这并不会导致“使用文件传输”。如果有join
方法可以获得计数,那么这可能没问题。
最初,决定跟踪目标的target1Name和target2Name,因为它们在创建审计记录时存在。我也需要这些名字(最近会这样做)。
目前,查询(上面缺少target1Name和target2Name列)在大约4秒内运行~2400万条记录。我们的目标是数亿,我们希望继续按照这些方式执行查询(希望将其保持在1-2分钟之内,但我们希望它能更好),但是我担心的是,一旦我们击中它赢得的大量数据(正在进行模拟其他行的工作)。
我不确定获取其他字段的最佳策略。如果我将这些列直接添加到select
中,我会丢失“使用索引”#39;在查询上。我尝试了一个join
回到表格中,这样可以保留'使用索引'但需要大约20秒。
我确实尝试将eventTime列更改为int而不是datetime,但这似乎不会影响索引的使用或时间。
答案 0 :(得分:4)
正如您可能理解的那样,这里的问题是范围条件ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00'
(它一直如此)打破了Transactions
索引的有效使用(即索引实际上仅用于clientId
} equation和范围条件的第一部分,索引不用于分组)。
通常,解决方案是使用等式检查替换范围条件(在您的情况下,将period
列,组eventTime
引入句点并将BETWEEN
子句替换为一个period IN (1,2,3,4,5)
)。但这可能成为你桌子的开销。
您可能尝试的另一个解决方案是添加另一个索引(如果不再使用,可能会替换Transactions
):(clientId, target1Id, type, eventTime)
,并使用以下查询:
SELECT
ae.target1Id,
ae.type,
COUNT(
NULLIF(ae.eventTime BETWEEN '2011-09-01 03:00:00'
AND '2012-09-30 23:57:00', 0)
) as cnt,
FROM AuditEvent ae
WHERE ae.clientId=4
GROUP BY ae.target1Id, ae.type;
这样,你将a)将范围条件移动到最后,b)允许使用索引进行分组,c)使索引成为查询的覆盖索引(即查询不需要磁盘IO操作)
<强> UPD1:强>
对不起,yesteday我没有仔细阅读你的帖子,也没有注意到你的问题是要检索target1Name
和target2Name
。首先,我不确定您是否正确理解Using index
的含义。缺少Using index
并不意味着没有索引用于查询,Using index
意味着索引本身包含足够的数据来执行子查询(即索引覆盖)。由于target1Name
和target2Name
未包含在任何索引中,因此获取它们的子查询将不会有Using index
。
如果您质疑如何将这两个字段添加到您的查询中(您认为足够快),请尝试以下操作:
SELECT a1.target1Id, a1.type, cnt, target1Name, target2Name
FROM (
select ae.target1Id, ae.type, count(*) as cnt, MAX(auditEventId) as max_id
from AuditEvent ae
where ae.clientId=4
and (ae.eventTime between '2011-09-01 03:00:00' and '2012-09-30 23:57:00')
group by ae.target1Id, ae.type) as a1
JOIN AuditEvent a2 ON a1.max_id = a2.auditEventId
;