【发布时间】:2012-10-13 10:36:08
【问题描述】:
这感觉就像是“为我做作业”之类的问题,但我真的被困在这里,试图让这个查询对一个有很多行的表快速运行。 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;
我最终也得到了“使用临时文件”和“使用文件排序”。我尝试删除count(*) 并改用select distinct,这不会导致“使用文件排序”。如果有办法返回join 以获取计数,这可能没问题。
最初,决定跟踪创建审计记录时存在的目标的 target1Name 和 target2Name。我也需要这些名字(最新的就可以了)。
目前,查询(上图,缺少 target1Name 和 target2Name 列)在大约 5 秒内运行约 2400 万条记录。我们的目标是数亿,我们希望查询继续沿着这些路线执行(希望将其保持在 1-2 分钟以内,但我们希望它做得更好),但我担心的是一次我们达到了它不会达到的大量数据(正在模拟更多的行)。
我不确定获取附加字段的最佳策略。如果我将列直接添加到select 中,我会丢失查询中的“使用索引”。我尝试将join 返回到表中,它保留了“使用索引”但大约需要 20 秒。
我确实尝试将 eventTime 列更改为 int 而不是 datetime,但这似乎并没有影响索引的使用或时间。
【问题讨论】:
-
你目前的查询时机是什么,“快速”下你了解什么?
-
你有关于 clientId 和 eventTime 的索引吗?还要验证您是否有那些您正在使用 eventTime 索引并且没有进行全表扫描。
-
您是否尝试过以下解决方法:1)将 DATETIME 更改为 INT; 2)通过client_id进行分区; 3) 数据现实性如何:数据是否有可能存在时间,并且可以移动到某种历史表中?
-
为什么没有人提到所使用的存储引擎和一切背后的硬件?通过设置正确的每个索引只能做这么多,其余的取决于硬件。并且不使用具有大 buffer_pool 的 InnoDB 意味着大量磁盘 IO 和具有约 400ish IOPS 的机械驱动器 - 当然,数百万行的性能会很糟糕。
-
@NickSpacek - here is some interesting reading,但大多数情况下您想要做的是增加名为
innodb_buffer_pool的变量 - 我通常将它放在可用 RAM 的 90% 左右。另一件事是您应该拥有能够超过 500 IOPS 的快速磁盘子系统(SSD 消灭那里的机械驱动器,范围从 40k IOPS 向上)。