我有一个临时表,有两个这样的记录:
select * into #Tbl from (select 1 id union select 2) tbl
以及相关索引:
Create nonclustered index IX_1 on #T(id)
以下查询需要 4000ms 才能运行:
SELECT AncestorId
FROM myView
WHERE AncestorId =ANY(select id from #t)
但等效查询(包含IN
和文字值)只需 3ms 即可运行!:
SELECT ProjectStructureId
FROM myView
WHERE AncestorId in (1,2)
为什么会出现这种巨大差异?如何将第一个查询更改为与第二个查询一样快?
P.S。
INNER JOIN
模型或EXISTS
模型无效IX_1 Index
更改为群集索引无效FORSEEK
没有帮助P.S.2
两者的执行计划可以在这里下载:https://www.dropbox.com/s/pas1ovyamqojhba/Query-With-In.sqlplan?dl=0
中的执行计划P.S。 3
视图定义是:
ALTER VIEW [dbo].[myView]
AS
WITH parents AS (SELECT main.Id, main.NodeTypeCode, main.ParentProjectStructureId AS DirectParentId, parentInfo.Id AS AncestorId, parentInfo.ParentProjectStructureId AS AncestorParentId, CASE WHEN main.NodeTypeCode <> IsNull(parentInfo.NodeTypeCode, 0)
THEN 1 ELSE 0 END AS AncestorTypeDiffLevel
FROM dbo.ProjectStructures AS main LEFT OUTER JOIN
dbo.ProjectStructures AS parentInfo ON main.ParentProjectStructureId = parentInfo.Id
UNION ALL
SELECT m.Id, m.NodeTypeCode, m.ParentProjectStructureId, parents.AncestorId, parents.AncestorParentId,
CASE WHEN m.NodeTypeCode <> parents.NodeTypeCode THEN AncestorTypeDiffLevel + 1 ELSE AncestorTypeDiffLevel END AS AncestorTypeDiffLevel
FROM dbo.ProjectStructures AS m INNER JOIN
parents ON m.ParentProjectStructureId = parents.Id)
SELECT ISNULL(Id, - 1) AS ProjectStructureId,
ISNULL(NodeTypeCode,-1) NodeTypeCode,
DirectParentId,
ISNULL(AncestorId, - 1) AS AncestorId,
AncestorParentId,
AncestorTypeDiffLevel
FROM parents
WHERE (AncestorId IS NOT NULL)
答案 0 :(得分:3)
在你的好计划中,它能够将文字值直接推送到递归CTE的锚点部分的索引查找中。
当他们来自桌子时拒绝这样做。
您可以创建表格类型
CREATE TYPE IntegerSet AS TABLE
(
Integer int PRIMARY KEY WITH (IGNORE_DUP_KEY = ON)
);
然后将其传递给内联TVF,直接在锚点部分使用。
然后就像把它叫做
DECLARE @AncestorIds INTEGERSET;
INSERT INTO @AncestorIds
VALUES (1),
(2);
SELECT *
FROM [dbo].[myFn](@AncestorIds);
内联TVF与视图大致相同,但
WHERE parentInfo.Id IN (SELECT Integer FROM @AncestorIds)
在递归CTE的锚点部分。
CREATE FUNCTION [dbo].[myFn]
(
@AncestorIds IntegerSet READONLY
)
RETURNS TABLE
AS
RETURN
WITH parents
AS (SELECT /*omitted for clarity*/
WHERE parentInfo.Id IN (SELECT Integer FROM @AncestorIds)
UNION ALL
SELECT/* Rest omitted for clarity*/
此外,您可以将LEFT JOIN
更改为INNER JOIN
,尽管优化商会为您执行此操作。
答案 1 :(得分:1)
我只想说我会将查询写成:
SELECT AncestorId
FROM myView
WHERE AncestorId IN (select id from #t);
我怀疑这会有所帮助。
问题是SQL Server可以比表中的值更好地优化文字值。结果是执行计划发生了变化。
如果IN
和JOIN
都没有解决问题,那么您可能需要调整视图的定义以提高性能。