我有一张包含超过1000万条记录的大表,它会继续增长。我正在对过去24小时的记录执行聚合查询(特定值的计数)。此查询所用的时间将随着表中记录的数量而增加。
我可以限制将这些24小时记录保存在单独的表中并在该表上执行聚合所花费的时间。 mysql是否提供了处理这种情况的任何功能?
表架构和查询供参考:
CREATE TABLE purchases (
Id int(11) NOT NULL AUTO_INCREMENT,
ProductId int(11) NOT NULL,
CustomerId int(11) NOT NULL,
PurchaseDateTime datetime(3) NOT NULL,
PRIMARY KEY (Id),
KEY ix_purchases_PurchaseDateTime (PurchaseDateTime) USING BTREE,
KEY ix_purchases_ProductId (ProductId) USING BTREE,
KEY ix_purchases_CustomerId (CustomerId) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
select COALESCE(sum(ProductId = v_ProductId), 0),
COALESCE(sum(CustomerId = v_CustomerId), 0)
into v_ProductCount, v_CustomerCount
from purchases
where PurchaseDateTime > NOW() - INTERVAL 1 DAY
and ( ProductId = v_ProductId
or CustomerId = v_CustomerId );
答案 0 :(得分:1)
建立并维护一个单独的Summary table。
使用分区,您可能会获得一些小改进,或者您可能没有任何改进。使用汇总表,您可以获得10倍的改进。
摘要表可能有1天的分辨率,或者您可能需要1小时。请提供SHOW CREATE TABLE
了解您目前拥有的内容,以便我们详细讨论。
(没有你想要的内置机制。)
答案 1 :(得分:0)
计划A
我会离开
INDEX(PurchaseDateTime, ProductId, CustomerId)
因为查询的其余部分无论如何都会处理它。
然后我会添加
SELECT
将覆盖"覆盖" - 也就是说,整个OR
可以在INDEX的BTree中执行。它也会被聚集在一起'在某种意义上,所有所需的数据将连续存储在索引中。是的,日期时间是刻意的。 (v_ProductId
对于优化非常麻烦。我不相信优化工具可以做"索引合并联盟"。)
计划B
如果您希望触摸很少的行(因为v_CustomerId
和SELECT COALESCE(sum(ProductId = v_ProductId), 0)
INTO v_ProductCount
FROM purchases
WHERE PurchaseDateTime > NOW() - INTERVAL 1 DAY
AND ProductId = v_ProductId;
SELECT COALESCE(sum(CustomerId = v_CustomerId), 0)
INTO v_CustomerCount
FROM purchases
WHERE PurchaseDateTime > NOW() - INTERVAL 1 DAY
AND CustomerId = v_CustomerId;
),那么以下内容可能会更快,尽管更复杂:
INDEX(ProductId, PurchaseDateTime),
INDEX(CustomerId, PurchaseDateTime)
与两者一起:
{{1}}
是的,列的顺序是故意不同的。
原始问题
这两种方法都比单独表格的原始建议更好。这些将数据隔离在索引的一部分(或两个索引)中,从而具有"分离的效果。而这些任务可以帮助您完成任务。