在 FK 字段上使用 WHERE 的非常慢的 SELECT 语句
Extremely slow SELECT statement with WHERE on a FK field
我在下面有这个查询,它非常慢。 运行 return 9900 万条记录中的 table 3,008 条记录几乎需要 2 分钟。它获取 "Article" 数据的第一个查询非常快,不到 1 秒,并且总是 returns 1 条记录。这是问题所在的第二个查询。我真的不想加入这些查询。第一个是如此之快,而且(在我的真实查询中)我设置的不仅仅是 @ArticleID 以供进一步使用。
查询执行计划说它在 IX_Name 上的集群键查找中有 75% 用于它,这对我来说没有意义,因为我在这里甚至没有对名称字段做任何事情。此外,Id 和 ArticleID 都是 ArticleAuthor 的索引,所以我不确定我做错了什么。 IX_Name 作为聚集索引,我无能为力...我的老板创建了这个 table 并说要那样做。
DECLARE @DOI VARCHAR(72) = '10.1140/EPJC/S10052-012-1993-2'
DECLARE @ArticleID VARCHAR(12)
SELECT
@ArticleID = A.Id
FROM
Article A
LEFT JOIN
JournalName JN WITH (NOLOCK) ON JN.Id = A.JournalId
WHERE
A.DOI = @DOI
PRINT 'GOT ARTICLE DATA ' + format(getdate(), 'yyyy-MM-dd HH:mm:ss.fff')
SELECT
AA.Id
FROM
[ArticleWarehouseTemp]..ArticleAuthor AA WITH (NOLOCK)
WHERE
AA.ArticleID = @ArticleID
PRINT 'GOT ARTICLEAUTHOR DATA ' + format(getdate(), 'yyyy-MM-dd HH:mm:ss.fff')
请帮忙!这让我发疯。我也在这里附加了 table 结构和索引。
CREATE TABLE [dbo].[ArticleAuthor]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[ArticleId] [int] NOT NULL,
[FullName] [nvarchar](128) NULL,
[LastName] [nvarchar](64) NULL,
[FirstName] [nvarchar](64) NULL,
[FirstInitial] [nvarchar](1) NULL,
[OrcId] [varchar](36) NULL,
[IsSequenceFirst] [bit] NULL,
[SequenceIndex] [smallint] NULL,
[CreatedDate] [smalldatetime] NULL CONSTRAINT [DF_ArticleAuthor_CreatedDate] DEFAULT (getdate()),
[UpdatedDate] [smalldatetime] NULL,
[Affiliations] [varbinary](max) NULL
) ON [ArticleAuthorFileGroup] TEXTIMAGE_ON [ArticleAuthorFileGroup]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[ArticleAuthor] WITH CHECK
ADD CONSTRAINT [FK_ArticleId]
FOREIGN KEY([ArticleId]) REFERENCES [dbo].[Article] ([Id])
GO
ALTER TABLE [dbo].[ArticleAuthor] CHECK CONSTRAINT [FK_ArticleId]
GO
CREATE NONCLUSTERED INDEX [IX_ID]
ON [dbo].[ArticleAuthor] ([Id] ASC)
CREATE NONCLUSTERED INDEX [IX_ArticleID]
ON [dbo].[ArticleAuthor] ([ArticleId] ASC)
CREATE CLUSTERED INDEX [IX_Name]
ON [dbo].[ArticleAuthor] ([LastName] ASC, [FirstName] ASC, [FirstInitial] ASC)
您正在声明 DECLARE @ArticleID VARCHAR(12) 而它在您的 table [dbo] 中是 int。[ArticleAuthor][ArticleId] [int] NOT NULL,
尝试使它们具有相同的数据类型以确保更快的响应。
如果您必须保持当前聚集索引不变,您可以执行以下操作:
1.
确保您使用的类型正确:
DECLARE @ArticleID VARCHAR(12)
应该是
DECLARE @ArticleID int;
匹配 ArticleAuthor
table 中列 ArticleId
的类型。
2.
为了确保索引 IX_ArticleID
被有效使用,使其成为覆盖索引,INCLUDE
列 Id
到它:
CREATE NONCLUSTERED INDEX [IX_ArticleID]
ON [dbo].[ArticleAuthor] ([ArticleId] ASC)
INCLUDE(Id);
3.
如果您的数据分布非常不均匀,即每 ArticleId
的行数因文章而异。比如说,如果一篇文章有 2 行而另一篇文章有百万行,那么您最好将 OPTION(RECOMPILE)
添加到查询中并确保统计信息 and/or 索引保持最新。
我在下面有这个查询,它非常慢。 运行 return 9900 万条记录中的 table 3,008 条记录几乎需要 2 分钟。它获取 "Article" 数据的第一个查询非常快,不到 1 秒,并且总是 returns 1 条记录。这是问题所在的第二个查询。我真的不想加入这些查询。第一个是如此之快,而且(在我的真实查询中)我设置的不仅仅是 @ArticleID 以供进一步使用。
查询执行计划说它在 IX_Name 上的集群键查找中有 75% 用于它,这对我来说没有意义,因为我在这里甚至没有对名称字段做任何事情。此外,Id 和 ArticleID 都是 ArticleAuthor 的索引,所以我不确定我做错了什么。 IX_Name 作为聚集索引,我无能为力...我的老板创建了这个 table 并说要那样做。
DECLARE @DOI VARCHAR(72) = '10.1140/EPJC/S10052-012-1993-2'
DECLARE @ArticleID VARCHAR(12)
SELECT
@ArticleID = A.Id
FROM
Article A
LEFT JOIN
JournalName JN WITH (NOLOCK) ON JN.Id = A.JournalId
WHERE
A.DOI = @DOI
PRINT 'GOT ARTICLE DATA ' + format(getdate(), 'yyyy-MM-dd HH:mm:ss.fff')
SELECT
AA.Id
FROM
[ArticleWarehouseTemp]..ArticleAuthor AA WITH (NOLOCK)
WHERE
AA.ArticleID = @ArticleID
PRINT 'GOT ARTICLEAUTHOR DATA ' + format(getdate(), 'yyyy-MM-dd HH:mm:ss.fff')
请帮忙!这让我发疯。我也在这里附加了 table 结构和索引。
CREATE TABLE [dbo].[ArticleAuthor]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[ArticleId] [int] NOT NULL,
[FullName] [nvarchar](128) NULL,
[LastName] [nvarchar](64) NULL,
[FirstName] [nvarchar](64) NULL,
[FirstInitial] [nvarchar](1) NULL,
[OrcId] [varchar](36) NULL,
[IsSequenceFirst] [bit] NULL,
[SequenceIndex] [smallint] NULL,
[CreatedDate] [smalldatetime] NULL CONSTRAINT [DF_ArticleAuthor_CreatedDate] DEFAULT (getdate()),
[UpdatedDate] [smalldatetime] NULL,
[Affiliations] [varbinary](max) NULL
) ON [ArticleAuthorFileGroup] TEXTIMAGE_ON [ArticleAuthorFileGroup]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[ArticleAuthor] WITH CHECK
ADD CONSTRAINT [FK_ArticleId]
FOREIGN KEY([ArticleId]) REFERENCES [dbo].[Article] ([Id])
GO
ALTER TABLE [dbo].[ArticleAuthor] CHECK CONSTRAINT [FK_ArticleId]
GO
CREATE NONCLUSTERED INDEX [IX_ID]
ON [dbo].[ArticleAuthor] ([Id] ASC)
CREATE NONCLUSTERED INDEX [IX_ArticleID]
ON [dbo].[ArticleAuthor] ([ArticleId] ASC)
CREATE CLUSTERED INDEX [IX_Name]
ON [dbo].[ArticleAuthor] ([LastName] ASC, [FirstName] ASC, [FirstInitial] ASC)
您正在声明 DECLARE @ArticleID VARCHAR(12) 而它在您的 table [dbo] 中是 int。[ArticleAuthor][ArticleId] [int] NOT NULL,
尝试使它们具有相同的数据类型以确保更快的响应。
如果您必须保持当前聚集索引不变,您可以执行以下操作:
1.
确保您使用的类型正确:
DECLARE @ArticleID VARCHAR(12)
应该是
DECLARE @ArticleID int;
匹配 ArticleAuthor
table 中列 ArticleId
的类型。
2.
为了确保索引 IX_ArticleID
被有效使用,使其成为覆盖索引,INCLUDE
列 Id
到它:
CREATE NONCLUSTERED INDEX [IX_ArticleID]
ON [dbo].[ArticleAuthor] ([ArticleId] ASC)
INCLUDE(Id);
3.
如果您的数据分布非常不均匀,即每 ArticleId
的行数因文章而异。比如说,如果一篇文章有 2 行而另一篇文章有百万行,那么您最好将 OPTION(RECOMPILE)
添加到查询中并确保统计信息 and/or 索引保持最新。