大 table 上的查询非常慢,我该如何优化?

Queries on large table extremely slow, how can I optimize?

我有一个数据库 table,大约有 325 万行。对于简单查询,我的查询时间非常慢,我不认为我在尝试做任何疯狂的事情。我对数据库优化的知识基本上为零,所以希望这是一个简单的修复。

table 持有合约数据记录,其中包含金额、日期和一些与其他 table 相关的 ID(VendorIdAgencyIdStateId), 这是数据库 table:

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]

我在数据库上有这 3 个索引。这些不是我创建的,看起来 Entity Framework Core 会自动进行迁移,所以它们可能是错误的。

CREATE NONCLUSTERED INDEX [IX_VendorContracts_AgencyId] 
ON [dbo].[VendorContracts] ([AgencyId] ASC)
         WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, 
               ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_VendorContracts_StateId] 
ON [dbo].[VendorContracts] ([StateId] ASC)
         WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, 
               ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IX_VendorContracts_VendorId] 
ON [dbo].[VendorContracts] ([VendorId] ASC)
         WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, 
               ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]

我的网站上有一个页面,我希望用户能够 select 一个供应商,并查看按州划分的合同总额。

我有这个查询:

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

但这需要很长时间,比如 15 - 20 分钟。

我尝试了其他更简单的查询,我想也许 SUM 正在减慢一切,但那些也非常慢。我尝试按供应商和州查询:

SELECT *
FROM [dbo].[VendorContracts]
WHERE VendorId = '...' AND StateId = '...'

即使它只有 returns 几千行,它仍然需要很长时间。

奇怪的是,我在单独的服务器上有另一个数据库,具有类似的 table,它有大约 600 万条记录,而且根本没有这样的问题。我可以在不到一两秒的时间内 运行 SUM 查询和其他查询。而且那个数据库 table 有相同的索引,所以不确定为什么那个数据库如此有效,而这个数据库却不是。

过去一周我每天都在插入数十万条记录,并且重新组织了索引,但这并没有解决问题,我还需要做些什么来优化它吗?我的数据库在 Azure 上,我是否需要更改或增加一些设置?

问题是您的索引没有覆盖您的查询。换句话说:服务器无法仅使用一个索引来为您的查询提供服务,因此它要么必须对每一行进行键查找,要么更有可能选择只扫描整个 table.

通常,正是由于这个原因,single-column 索引不是很有用。您可以更改现有索引之一。

  • 您希望 WHERE 中的等式 = 谓词成为索引键中的第一列。
  • 然后添加连接列和分组列。通常只值得在此阶段添加其中之一,除非连接是基于唯一值的。
  • 最后,添加所有其他列。这些不一定是键的一部分,它们可以是 INCLUDE 列。

例如:

CREATE NONCLUSTERED INDEX [IX_VendorContracts_VendorId] ON [dbo].[VendorContracts]
  (VendorId, StateId)
INCLUDE
  (ContractAmount)
WITH (DROP_EXISTING = ON, ONLINE = ON);