使用DateTime和group by上的聚合加速SQL查询
我的MS SQL数据库中有一个大于1亿行的大型表,其中包含以下列:使用DateTime和group by上的聚合加速SQL查询,sql,sql-server,sqlperformance,Sql,Sql Server,Sqlperformance,我的MS SQL数据库中有一个大于1亿行的大型表,其中包含以下列: Id int not null, ObjectId int not null, Timestamp datetime not null State int not null 将其标识为表的主键,并在其上具有聚集索引。我按此顺序在Timestamp和ObjectId上添加了一个非聚集索引。ObjectId中只有大约2000个不同的值。我现在要执行以下查询: SELECT ObjectId, MAX(Timestamp) FROM
Id int not null,
ObjectId int not null,
Timestamp datetime not null
State int not null
将其标识为表的主键,并在其上具有聚集索引。我按此顺序在Timestamp和ObjectId上添加了一个非聚集索引。ObjectId中只有大约2000个不同的值。我现在要执行以下查询:
SELECT ObjectId, MAX(Timestamp) FROM Table GROUP BY ObjectId
大约需要四秒钟,这对我的应用程序来说太慢了。执行计划指出,97%的运行时用于非聚集索引的索引扫描
在表的一个副本上,我在ObjectId和Timestamp上创建了一个聚集索引。结果运行时是相同的,执行计划说它现在正在对聚集索引进行索引扫描
在不将表的数据拆分为多个表的情况下,是否还有其他方法可以提高运行时间?4秒对于在数据库中处理超过100M行的数据来说,这并不坏。 您可以每天归档另一个表中的某些数据以保留历史记录。您可以归档另一个表中的所有数据,并删除对象的旧更改:
delete from TABLE where Id in (select t1.Id from Table t1, Table t2
where t1.ObjectId = t2.ObjectId and t1.Timestamp < t2.Timestamp )
对于这个特定的查询,ObjectId上的索引、时间戳将是最佳的。ObjectId、Timestamp DESC有可能执行得更快。我可以向您提出另一个答案,添加一个布尔列LAST,并将ObjectId的LAST true更新为false,然后将此ObjectId的LAST now行插入LAST to true。在ObjectID和LAST上创建索引。查询非常简单:
SELECT ObjectId, Timestamp FROM Table where LAST = true
不再有group by和fullscan,但每个insert都有一个更新。不,这真的很糟糕,4s大约太多了:我的问题明确排除了将部分数据复制到另一个表的解决方案。因此,您可以购买更好的机器,或者在my.cnf文件中微调MySQL key_buffer_大小,以增加索引的ram使用率,但您可以放置好的索引。数据库中的数据需要存档您不能认为您的模型可以无限增长而不会出现性能问题。关键是,上面的查询具有一个线性依赖于表中行数的运行时。这是次优的,不管表中有一百万行还是十亿行。只要执行计划说它扫描整个表,在开始某些存档技术之前,就有一些需要改进的地方。它扫描整个索引,而不是通过记录行数和算法的最佳性能来实现的线性byt。您是否仅在ObjectID上尝试过索引?尽管我不认为这会改善问题,因为您执行的查询在任何情况下都需要触及数据库中的每一行。在我看来,如果不升级数据库服务器或重新设计架构,就不可能有任何改进。例如,您可以添加第二个表,使用触发器为每个objectid保留最大时间戳。@jeroenh:Yes,我也试过了,但没有任何显著的结果。事实上,我们可以假设,您是否经常在这个表中插入数据,可能会在您的查询中添加一个提示:使用NOLOCKGood idea。我试过这个,效果非常好。额外的更新并不重要。它很快,对于我来说,SELECT语句的运行时更为重要。