需要提高性能查询 table 具有数百万行 - SQL 服务器
Need to improve performance query a table with millions of rows - SQL Server
审计线索上的查询 table 一旦性能测试(读取和插入)中的负载增加并且我已尽我所能地建立索引,速度就会开始变慢。有了这个查询和这些 table 和索引,我还能做什么?
CREATE TABLE [dbo].[mod2] (
[id] [int] IDENTITY,
[userId] [int] NOT NULL,
[epochTime] [bigint] NOT NULL,
[forecastId] [int] NOT NULL,
[description] [char](12) NOT NULL,
[auxText] [text] NULL,
[auxDate] [date] NULL
);
ALTER TABLE [dbo].[mod2] ADD CONSTRAINT PK_mod2 PRIMARY KEY(ID);
ALTER TABLE [dbo].[mod2] WITH CHECK
ADD CONSTRAINT [FK_mod2_forecastId] FOREIGN KEY([forecastId])
REFERENCES [dbo].[forecast] ([id]);
ALTER TABLE [dbo].[mod2] CHECK CONSTRAINT [FK_mod2_forecastId];
ALTER TABLE [dbo].[mod2] WITH CHECK
ADD CONSTRAINT [FK_mod2_userId] FOREIGN KEY([userId])
REFERENCES [dbo].[user] ([id]);
ALTER TABLE [dbo].[mod2] CHECK CONSTRAINT [FK_mod2_userId];
CREATE NONCLUSTERED INDEX IX_modification_auxDate ON [dbo].[mod2] (auxDate ASC);
CREATE NONCLUSTERED INDEX IX_modification_epochTime ON [dbo].[mod2] (epochTime ASC);
CREATE NONCLUSTERED INDEX IX_modification_description ON [dbo].[mod2] (description ASC);
CREATE NONCLUSTERED INDEX IX_modification_forecastId ON [dbo].[mod2] (forecastId ASC);
CREATE NONCLUSTERED INDEX IX_modification_userId ON [dbo].[mod2] (userId ASC);
这是我的查询:
SELECT name, epochTime, auxDate
FROM mod2 WITH (NOLOCK)
JOIN [user] ON [user].id = mod2.userId
WHERE forecastId = ? AND description = ? AND auxDate = ?
这是一个遗留系统,在我将这些索引放在上面并将 description
字段从 VARCHAR
更改为 CHAR
之前它正在爬行
预测和用户 id
字段 INT
和索引类似。
您可以在此处执行一些操作。
一个是确保 user
上的 id
字段有聚簇索引(可能有,但确保不会造成伤害)。
您放入的单个索引不是很好 - 特别是考虑到您显示的查询模式 - 要么不使用它们(因为它们不包含完整数据),要么可能使用其中一些然后将引用完整的 table 以挑选出完成查询所需的剩余数据。
对于此特定查询,对于 mod2
,我可能会在 userId
上添加一个索引 covering forecastId
、description
和 auxDate
- 这样索引包含完成查询所需的所有数据(在 mod2
端)。
CREATE NONCLUSTERED INDEX IXmod2_user_desc_forecast_auxdate
ON [dbo].[mod2] (userId, forecastId, description, auxDate DESC);
查询计划如下所示:
|--Nested Loops(Inner Join, OUTER REFERENCES:([MyDB].[dbo].[mod2].[id]) OPTIMIZED)
|--Nested Loops(Inner Join, OUTER REFERENCES:([MyDB].[dbo].[user].[id], [Expr1006]) WITH UNORDERED PREFETCH)
| |--Clustered Index Scan(OBJECT:([MyDB].[dbo].[user]. [PK_user]), ORDERED FORWARD)
| |--Index Seek(OBJECT:([MyDB].[dbo].[mod2].[IX_mod2_user_desc_forecast_auxdate]), SEEK:([MyDB].[dbo].[mod2].[userId]=[MyDB].[dbo].[user].[id] AND [MyDB].[dbo].[mod2].[forecastId]=(40357) AND [MyDB].[dbo].[mod2].[description]='SAVE' AND [MyDB].[dbo].[mod2].[auxDate]='2017-01-31') ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([MyDB].[dbo].[mod2].[PK_mod2]), SEEK:([MyDB].[dbo].[mod2].[id]=[MyDB].[dbo].[mod2].[id]) LOOKUP ORDERED FORWARD)
审计线索上的查询 table 一旦性能测试(读取和插入)中的负载增加并且我已尽我所能地建立索引,速度就会开始变慢。有了这个查询和这些 table 和索引,我还能做什么?
CREATE TABLE [dbo].[mod2] (
[id] [int] IDENTITY,
[userId] [int] NOT NULL,
[epochTime] [bigint] NOT NULL,
[forecastId] [int] NOT NULL,
[description] [char](12) NOT NULL,
[auxText] [text] NULL,
[auxDate] [date] NULL
);
ALTER TABLE [dbo].[mod2] ADD CONSTRAINT PK_mod2 PRIMARY KEY(ID);
ALTER TABLE [dbo].[mod2] WITH CHECK
ADD CONSTRAINT [FK_mod2_forecastId] FOREIGN KEY([forecastId])
REFERENCES [dbo].[forecast] ([id]);
ALTER TABLE [dbo].[mod2] CHECK CONSTRAINT [FK_mod2_forecastId];
ALTER TABLE [dbo].[mod2] WITH CHECK
ADD CONSTRAINT [FK_mod2_userId] FOREIGN KEY([userId])
REFERENCES [dbo].[user] ([id]);
ALTER TABLE [dbo].[mod2] CHECK CONSTRAINT [FK_mod2_userId];
CREATE NONCLUSTERED INDEX IX_modification_auxDate ON [dbo].[mod2] (auxDate ASC);
CREATE NONCLUSTERED INDEX IX_modification_epochTime ON [dbo].[mod2] (epochTime ASC);
CREATE NONCLUSTERED INDEX IX_modification_description ON [dbo].[mod2] (description ASC);
CREATE NONCLUSTERED INDEX IX_modification_forecastId ON [dbo].[mod2] (forecastId ASC);
CREATE NONCLUSTERED INDEX IX_modification_userId ON [dbo].[mod2] (userId ASC);
这是我的查询:
SELECT name, epochTime, auxDate
FROM mod2 WITH (NOLOCK)
JOIN [user] ON [user].id = mod2.userId
WHERE forecastId = ? AND description = ? AND auxDate = ?
这是一个遗留系统,在我将这些索引放在上面并将 description
字段从 VARCHAR
更改为 CHAR
预测和用户 id
字段 INT
和索引类似。
您可以在此处执行一些操作。
一个是确保 user
上的 id
字段有聚簇索引(可能有,但确保不会造成伤害)。
您放入的单个索引不是很好 - 特别是考虑到您显示的查询模式 - 要么不使用它们(因为它们不包含完整数据),要么可能使用其中一些然后将引用完整的 table 以挑选出完成查询所需的剩余数据。
对于此特定查询,对于 mod2
,我可能会在 userId
上添加一个索引 covering forecastId
、description
和 auxDate
- 这样索引包含完成查询所需的所有数据(在 mod2
端)。
CREATE NONCLUSTERED INDEX IXmod2_user_desc_forecast_auxdate
ON [dbo].[mod2] (userId, forecastId, description, auxDate DESC);
查询计划如下所示:
|--Nested Loops(Inner Join, OUTER REFERENCES:([MyDB].[dbo].[mod2].[id]) OPTIMIZED)
|--Nested Loops(Inner Join, OUTER REFERENCES:([MyDB].[dbo].[user].[id], [Expr1006]) WITH UNORDERED PREFETCH)
| |--Clustered Index Scan(OBJECT:([MyDB].[dbo].[user]. [PK_user]), ORDERED FORWARD)
| |--Index Seek(OBJECT:([MyDB].[dbo].[mod2].[IX_mod2_user_desc_forecast_auxdate]), SEEK:([MyDB].[dbo].[mod2].[userId]=[MyDB].[dbo].[user].[id] AND [MyDB].[dbo].[mod2].[forecastId]=(40357) AND [MyDB].[dbo].[mod2].[description]='SAVE' AND [MyDB].[dbo].[mod2].[auxDate]='2017-01-31') ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([MyDB].[dbo].[mod2].[PK_mod2]), SEEK:([MyDB].[dbo].[mod2].[id]=[MyDB].[dbo].[mod2].[id]) LOOKUP ORDERED FORWARD)