SQL 服务器查询过滤器的顺序很慢
SQL Server Query filter with order is slow
我为此苦恼了一段时间。
我有一个包含三个表(每个表都有数百万条记录)的数据库,如下(为简单起见删除了一些列):
1.[Entity]
[Id] UNIQUEIDENTIFIER PK,
[EntityLevel_Id] UNIQUEIDENTIFIER NOT NULL FK [EntityLevel] ([Id])
2.[EntityData]
[Id] UNIQUEIDENTIFIER PK,
[Entity_Id] UNIQUEIDENTIFIER NOT NULL FK [Entity] ([Id]),
[DataLanguage_Id] UNIQUEIDENTIFIER NOT NULL FK [Language] ([Id]),
[Code] NVARCHAR (250) NOT NULL
3.[EntityLevel]
[Id] UNIQUEIDENTIFIER PK,
[Sort] INT NOT NULL
存在索引如下
[IX_Entity_EntityLevelId] ON [Entity] ([EntityLevel_Id])
[IX_EntityData_EntityId] ON [EntityData] ([Entity_Id])
[IX_EntityData_DataLanguageId_Code] ON [EntityData] ([DataLanguage_Id], [Code])
[IX_EntityLevel_Sort] ON [EntityLevel] ([Sort])
为了消除缓慢是因为 selected 列的可能性,我只 select 一个固定值
以下查询运行速度非常快(不到 1 秒):
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
以下查询也运行得非常快:
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
ORDER BY
[EntityData].[Code] ASC
下面的也运行得很快:
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityLevel].[Sort] = 1
但是,以下查询运行非常慢(大约 10 秒):
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
AND
[EntityLevel].[Sort] = 1
ORDER BY
[EntityData].[Code]
我不知道原因,也找不到任何方法来应用更多索引以使查询运行得更快
感谢任何帮助!
编辑:
以下查询也运行得很快:
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
AND
[EntityLevel].[Sort] = 1
和
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityLevel].[Sort] = 1
ORDER BY
[EntityData].[Code]
问题只出现在 order by 和两个过滤器上
在
上尝试索引
[Entity] ([Id], [EntityLevel_Id])
,
[EntityData] ([DataLanguage_Id], [Entity_id], [Code])
和
[EntityLevel] ([Sort], [Id])
.
试验列的顺序。对于 2. 和 3. 我假设 WHERE
子句中的 [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
和 [EntityLevel].[Sort] = 1
比连接过滤得更多。但我不知道数据,这个假设可能是错误的。
你的问题是关于这个查询的:
SELECT TOP 20 1
FROM [Entity] JOIN
[EntityData]
ON [Entity].[Id] = [EntityData].[Entity_Id] JOIN
[EntityLevel]
ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265' AND
[EntityLevel].[Sort] = 1
ORDER BY [EntityData].[Code];
我认为问题是 SQL 服务器无法使用索引进行排序。您可以使用 EXISTS
:
来解决这个问题
SELECT TOP 20 1
FROM Entity e JOIN
EntityData ed
ON e.Id = ed.Entity_Id
WHERE ed.DataLanguage_Id = 'B6930015-F177-4ED3-97B0-AAEF401F9265' AND
EXISTS (SELECT 1
FROM EntityLevel el
WHERE e.EntityLevel_Id = el.Id AND
el.Sort = 1
)
ORDER BY ed.Code;
对于此版本,您需要 EntityLevel(ID, Sort)
上的索引。
这 可能 允许 SQL 引擎使用索引进行排序(就像在其他情况下一样)。当然,您不能 select 来自 EntityLevel
的任何列——但是您的示例查询无论如何都不会这样做。
对于任何关心的人,这是问题的解决方案:
事实证明,有那么多行,由于索引不同,需要时间进行键查找和哈希匹配,因此解决方案是添加以下索引以允许在 table 对于所有过滤器(和排序依据)值:
CREATE NONCLUSTERED INDEX [IX_EntityData_EntityId_DataLanguageId_IncCode] ON [EntityData] ([Entity_Id], [DataLanguage_Id]) INCLUDE ([Code])
但是由于我在某些情况下也可能会按代码进行过滤,而不仅仅是使用order by,所以我将索引修改为这样:
CREATE NONCLUSTERED INDEX [IX_EntityData_EntityId_DataLanguageId_Code] ON [EntityData] ([Entity_Id], [DataLanguage_Id], [Code])
我为此苦恼了一段时间。
我有一个包含三个表(每个表都有数百万条记录)的数据库,如下(为简单起见删除了一些列):
1.[Entity]
[Id] UNIQUEIDENTIFIER PK,
[EntityLevel_Id] UNIQUEIDENTIFIER NOT NULL FK [EntityLevel] ([Id])
2.[EntityData]
[Id] UNIQUEIDENTIFIER PK,
[Entity_Id] UNIQUEIDENTIFIER NOT NULL FK [Entity] ([Id]),
[DataLanguage_Id] UNIQUEIDENTIFIER NOT NULL FK [Language] ([Id]),
[Code] NVARCHAR (250) NOT NULL
3.[EntityLevel]
[Id] UNIQUEIDENTIFIER PK,
[Sort] INT NOT NULL
存在索引如下
[IX_Entity_EntityLevelId] ON [Entity] ([EntityLevel_Id])
[IX_EntityData_EntityId] ON [EntityData] ([Entity_Id])
[IX_EntityData_DataLanguageId_Code] ON [EntityData] ([DataLanguage_Id], [Code])
[IX_EntityLevel_Sort] ON [EntityLevel] ([Sort])
为了消除缓慢是因为 selected 列的可能性,我只 select 一个固定值
以下查询运行速度非常快(不到 1 秒):
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
以下查询也运行得非常快:
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
ORDER BY
[EntityData].[Code] ASC
下面的也运行得很快:
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityLevel].[Sort] = 1
但是,以下查询运行非常慢(大约 10 秒):
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
AND
[EntityLevel].[Sort] = 1
ORDER BY
[EntityData].[Code]
我不知道原因,也找不到任何方法来应用更多索引以使查询运行得更快
感谢任何帮助!
编辑: 以下查询也运行得很快:
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
AND
[EntityLevel].[Sort] = 1
和
SELECT TOP 20
1
FROM
[Entity]
INNER JOIN [EntityData] ON [Entity].[Id] = [EntityData].[Entity_Id]
INNER JOIN [EntityLevel] ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE
[EntityLevel].[Sort] = 1
ORDER BY
[EntityData].[Code]
问题只出现在 order by 和两个过滤器上
在
上尝试索引[Entity] ([Id], [EntityLevel_Id])
,[EntityData] ([DataLanguage_Id], [Entity_id], [Code])
和[EntityLevel] ([Sort], [Id])
.
试验列的顺序。对于 2. 和 3. 我假设 WHERE
子句中的 [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265'
和 [EntityLevel].[Sort] = 1
比连接过滤得更多。但我不知道数据,这个假设可能是错误的。
你的问题是关于这个查询的:
SELECT TOP 20 1
FROM [Entity] JOIN
[EntityData]
ON [Entity].[Id] = [EntityData].[Entity_Id] JOIN
[EntityLevel]
ON [Entity].[EntityLevel_Id] = [EntityLevel].[Id]
WHERE [EntityData].[DataLanguage_Id] = 'B6930015-F177-4ED3-97B0-AAEF401F9265' AND
[EntityLevel].[Sort] = 1
ORDER BY [EntityData].[Code];
我认为问题是 SQL 服务器无法使用索引进行排序。您可以使用 EXISTS
:
SELECT TOP 20 1
FROM Entity e JOIN
EntityData ed
ON e.Id = ed.Entity_Id
WHERE ed.DataLanguage_Id = 'B6930015-F177-4ED3-97B0-AAEF401F9265' AND
EXISTS (SELECT 1
FROM EntityLevel el
WHERE e.EntityLevel_Id = el.Id AND
el.Sort = 1
)
ORDER BY ed.Code;
对于此版本,您需要 EntityLevel(ID, Sort)
上的索引。
这 可能 允许 SQL 引擎使用索引进行排序(就像在其他情况下一样)。当然,您不能 select 来自 EntityLevel
的任何列——但是您的示例查询无论如何都不会这样做。
对于任何关心的人,这是问题的解决方案:
事实证明,有那么多行,由于索引不同,需要时间进行键查找和哈希匹配,因此解决方案是添加以下索引以允许在 table 对于所有过滤器(和排序依据)值:
CREATE NONCLUSTERED INDEX [IX_EntityData_EntityId_DataLanguageId_IncCode] ON [EntityData] ([Entity_Id], [DataLanguage_Id]) INCLUDE ([Code])
但是由于我在某些情况下也可能会按代码进行过滤,而不仅仅是使用order by,所以我将索引修改为这样:
CREATE NONCLUSTERED INDEX [IX_EntityData_EntityId_DataLanguageId_Code] ON [EntityData] ([Entity_Id], [DataLanguage_Id], [Code])