pab*_*lox 9 sql t-sql sql-server events
我有一张约有2000多万条记录的表格.
结构如下:
EventId UNIQUEIDENTIFIER
SourceUserId UNIQUEIDENTIFIER
DestinationUserId UNIQUEIDENTIFIER
CreatedAt DATETIME
TypeId INT
MetaId INT
Run Code Online (Sandbox Code Playgroud)
表每天接收大约10万条记录.
我在除MetaId之外的每一列都有索引,因为它没有在'where'子句中使用
问题是当我想要拿起例如.所需SourceUserId的最新100条记录
查询有时最多需要4分钟才能执行,这是不可接受的.
例如.
SELECT TOP 100 * FROM Events WITH (NOLOCK)
WHERE SourceUserId = '15b534b17-5a5a-415a-9fc0-7565199c3461'
AND
(
TypeId IN (2, 3, 4)
OR
(TypeId = 60 AND SrcMemberId != DstMemberId)
)
ORDER BY CreatedAt DESC
Run Code Online (Sandbox Code Playgroud)
我无法进行分区等,因为我使用的是标准版的SQL Server,而且Enterprise太贵了.
我也认为这张表很小很慢.
我认为问题在于ORDER BY子句,因为db必须经历更大的数据集.
任何想法如何使它更快?
也许关系型数据库对于那种数据不是一个好主意.
始终通过CreatedAt DESC订购数据
谢谢你的阅读.
PabloX
boy*_*dc7 15
您可能希望为此类查询创建复合索引 - 当查询运行缓慢时,很可能选择扫描CreatedAt列上的索引并对SourceUserId值执行残差过滤,实际上是什么想要发生的是直接跳转到正确排序的给定SourceUserId的所有记录 - 要实现这一点,你需要主要在SourceUserId上创建一个复合索引(执行相等性检查),然后在CreateAt上创建一个复合索引(以保留一个给定SourceUserId值).您可能还想尝试添加TypeId,具体取决于此列的选择性.
因此,最有可能提供最佳可重复性能的2(尝试它们并进行比较)将是:
与往常一样,在确定索引的方式/内容/位置时还需要考虑许多其他因素,正如Remus在单独的答案中讨论的那样,一个重要的考虑因素是覆盖查询与保持查找.此外,您还需要考虑写入卷,可能的碎片影响(如果有),单例查找与大型顺序扫描等等.
除了MetaId,我在每列上都有索引
非覆盖索引可能会达到"临界点",查询将恢复为表扫描.只是在每个列上添加索引,因为它在where子句中使用并不等于良好的索引设计.以您的查询为例,一个好的100%覆盖索引将是:
INDEX ON (SourceUserId , CreatedAt) INCLUDE (TypeId, SrcMemberId, DstMemberId)
Run Code Online (Sandbox Code Playgroud)
以下索引也很有用,尽管它仍然会导致查找:
INDEX ON (SourceUserId , CreatedAt) INCLUDE (TypeId)
Run Code Online (Sandbox Code Playgroud)
最后一个没有任何包含列的索引可能会有所帮助,但同样可能会被忽略(取决于列统计和基数估计):
INDEX ON (SourceUserId , CreatedAt)
Run Code Online (Sandbox Code Playgroud)
但是,对于您的查询,SourceUSerId上的单独索引和CreatedAt上的单独索引基本无用.
请参阅索引设计基础知识.
表具有基于GUID值构建的索引,这表明可能会影响性能的一系列问题:
这里有几个关于如何调查和解决这些问题的资源: