优化递归查询的 CTE
我有一张带有自连接的桌子。您可以将结构视为表示组织层次结构的标准表。例如表:-
MemberId
MemberName
RelatedMemberId
该表由 50000 条样本记录组成。我写了 CTE 递归查询,它工作得很好。然而,在我的机器(4GB RAM、2.4 Ghz Core2Duo、7200 RPM HDD)上处理 50000 条记录所需的时间约为 3 分钟。
我怎样才能提高性能,因为 50000 并不是一个很大的数字。随着时间的推移,它会不断增加。这正是我的存储过程中的查询。该查询的目的是选择特定成员下的所有成员。例如。每个人都在公司所有者的领导下。对于管理者,除了所有者之外,所有记录都会被返回。我希望您了解查询的目的。
设置 ANSI_NULLS 为开 去 将 QUOTED_IDENTIFIER 设置为 ON 正如
Alter PROCEDURE spGetNonVirtualizedData
(
@MemberId int
)
AS
BEGIN
With MembersCTE As
(
Select parent.MemberId As MemberId, 0 as Level
From Members as parent Where IsNull(MemberId,0) = IsNull(@MemberId,0)
Union ALL
Select child.MemberId As MemberId , Level + 1 as Level
From Members as child
Inner Join MembersCTE on MembersCTE.MemberId = child.RelatedMemberId
)
Select Members.*
From MembersCTE
Inner Join Members On MembersCTE.MemberId = Members.MemberId
option(maxrecursion 0)
END
GO
您所看到的,为了提高性能,我什至在选择记录时在最后一步进行了联接,以便所有不必要的记录都不会插入到临时表中。如果我在 CTE 的基本步骤和递归步骤中进行连接(而不是最后一步的选择),则查询需要 20 分钟才能执行!
MemberId 是表中的主键。
提前致谢 :)
I have a table with self join. You can think of the structure as standard table to represent organisational hierarchy. Eg table:-
MemberId
MemberName
RelatedMemberId
This table consists of 50000 sample records. I wrote CTE recursive query and it works absolutely fine. However the time it takes to process just 50000 records is round about 3 minutes on my machine (4GB Ram, 2.4 Ghz Core2Duo, 7200 RPM HDD).
How can I possibly improve the performance because 50000 is not so huge number. Over time it will keep on increasing. This is the query which is exactly what I have in my Stored Procedure. The query's purpose is to select all the members that come under a specific member. Eg. Under Owner of the company each and every person comes. For Manager, except Owner all of the records gets returned. I hope you understand the query's purpose.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE spGetNonVirtualizedData
(
@MemberId int
)
AS
BEGIN
With MembersCTE As
(
Select parent.MemberId As MemberId, 0 as Level
From Members as parent Where IsNull(MemberId,0) = IsNull(@MemberId,0)
Union ALL
Select child.MemberId As MemberId , Level + 1 as Level
From Members as child
Inner Join MembersCTE on MembersCTE.MemberId = child.RelatedMemberId
)
Select Members.*
From MembersCTE
Inner Join Members On MembersCTE.MemberId = Members.MemberId
option(maxrecursion 0)
END
GO
As you can see to improve the performance, I have even made the Joins at the last step while selecting records so that all unnecessary records do not get inserted into temp table. If I made joins in my base step and recursive step of CTE (instead of Select at the last step) the query takes 20 minutes to execute!
MemberId is primary key in the table.
Thanks in advance :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在您的锚条件中,您有
Where IsNull(MemberId,0) = IsNull(@MemberId,0)
我认为这只是因为当您将NULL
作为参数传递时=
无法返回IS NULL
值。这将导致扫描而不是查找。使用
WHERE MemberId = @MemberId OR (@MemberId IS NULL AND MemberId IS NULL)
来代替可控制的。另外,我假设您无法在
RelatedMemberId
上建立索引。如果不是,您应该添加一个(尽管如果
MemberId
是聚集索引键,您可以跳过包含的列位,因为它将自动包含在内)In your anchor condition you have
Where IsNull(MemberId,0) = IsNull(@MemberId,0)
I assume this is just because when you passNULL
as a parameter=
doesn't work in terms of bringing backIS NULL
values. This will cause a scan rather than a seek.Use
WHERE MemberId = @MemberId OR (@MemberId IS NULL AND MemberId IS NULL)
instead which is sargable.Also I'm assuming that you can't have an index on
RelatedMemberId
. If not you should add one(though you can skip the included column bit if
MemberId
is the clustered index key as it will be included automatically)