大 table 上的查询非常慢,我该如何优化?
Queries on large table extremely slow, how can I optimize?
我有一个数据库 table,大约有 325 万行。对于简单查询,我的查询时间非常慢,我不认为我在尝试做任何疯狂的事情。我对数据库优化的知识基本上为零,所以希望这是一个简单的修复。
table 持有合约数据记录,其中包含金额、日期和一些与其他 table 相关的 ID(VendorId
、AgencyId
、StateId
), 这是数据库 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);
我有一个数据库 table,大约有 325 万行。对于简单查询,我的查询时间非常慢,我不认为我在尝试做任何疯狂的事情。我对数据库优化的知识基本上为零,所以希望这是一个简单的修复。
table 持有合约数据记录,其中包含金额、日期和一些与其他 table 相关的 ID(VendorId
、AgencyId
、StateId
), 这是数据库 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);