繁体   English   中英

即使有索引,对数百万条记录的 SUM 查询也很慢,我该如何优化?

[英]SUM query on millions of records is slow even with indexes, how can I optimize?

我有一个包含大约 350 万条记录的数据库表。 该表包含合同数据记录,其中包含金额、日期和一些与其他表相关的 ID(VendorId、AgencyId、StateId),这是数据库表:

CREATE TABLE [dbo].[VendorContracts]
(
    [Id] [uniqueidentifier] NOT NULL,   
    [ContractDate] [datetime2](7) NOT NULL,
    [ContractAmount] [decimal](19, 4) NULL, 
    [VendorId] [uniqueidentifier] NOT NULL,
    [AgencyId] [uniqueidentifier] NOT NULL,
    [StateId] [uniqueidentifier] NOT NULL,

    [CreatedBy] [nvarchar](max) NULL,
    [CreatedDate] [datetime2](7) NOT NULL,
    [LastModifiedBy] [nvarchar](max) NULL,
    [LastModifiedDate] [datetime2](7) NULL,
    [IsActive] [bit] NOT NULL,

    CONSTRAINT [PK_VendorContracts] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
                WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, 
                      OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

我在我的网站上有一个页面,我希望用户能够 select 一个供应商,并查看合同总额,除以 state。

我有这个查询:

SELECT SUM(ContractAmount), StateId
FROM [dbo].[VendorContracts]
WHERE VendorId = '...'
GROUP BY StateId

我创建了这个索引来帮助解决这个问题:

CREATE NONCLUSTERED INDEX [IX_VendorContracts_VendorId] ON [dbo].[VendorContracts]
(
    [VendorId] ASC
)
INCLUDE([Id],[StateId],[ContractAmount],[ContractDate],[AgencyId]) 
WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF)

这对我的大多数供应商都非常有效,我可以在一两秒内很快得到结果。 但是有几个供应商,每个供应商都有大约 100 万条记录,而这些需要很长时间,通常是几分钟。

所以我想知道是否有任何方法可以通过修改我的索引来进一步优化? 还是有其他办法?

或者我可能会做错这个? 不确定在 100 万条记录上运行如此庞大的SUM查询是否不是执行此操作的好方法。 记录不会经常添加到该表中,我们可能每月添加几千条记录一次或两次,所以我在考虑可能有一个夜间进程来获取SUM数据并将它们存储在一个单独的表中,然后查询当我需要运行报告时。

你应该接受查询...

SELECT SUM(ContractAmount) AS TotalContractAmount,
       VendorId,
       StateId
FROM   [dbo].[VendorContracts]
GROUP  BY VendorId,
          StateId

...并使其成为索引视图,以便系统自动预先计算和维护结果(在VendorId, StateId上具有唯一的聚集索引)。

索引视图可能有数据修改的开销,但你说

记录不是很频繁地添加到这个表中,我们可能一个月添加几千条一两次,

SQL 服务器应该在 Azure SQL 数据库上自动进行索引视图匹配,并识别索引视图可以提供原始查询。

如果您发现这种匹配没有发生(验证执行计划),那么您可能需要求助于从索引视图中显式选择并使用NOEXPAND提示。

如果您有一个可操作的数据库系统,您希望在其中进行一些报告,那么您应该考虑在 Azure SQL 数据库中使用列存储索引。 它支持集群和非集群列存储。 列存储非常适合报告/分析,因为与 B 树/堆相比,它们是高度压缩的,而且因为有一个称为批处理模式的优化执行引擎,它对于像报告查询这样的大量行的查询效率要高得多。

您可以在文档页面阅读有关语法的信息。

在不了解您的工作负载的情况下,我无法确定您应该使用集群还是非集群。 但是,尝试非集群化以查看它是否对您的应用程序有帮助相对容易。 虽然索引视图可用于使特定查询模式 go 更快,但它确实有一些限制 - 例如,如果您在主表上发生大量更新,那么这些更新查询现在必须同时锁定两个主表+ 索引以及索引视图上的索引。 这可能会导致锁阻塞。 通过非聚集列存储索引尝试批处理模式(如果没有,您将希望移动到兼容模式 150 以获得最新/最大的性能增强),看看这是否能解决您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM