我有三个表定义成员和表格的表格。组配置文件如下:
[tbMember] (1M记录):MemberID(PK)|会员名称|年龄|性
[tbGroup] (10K记录):GroupID(PK)| GroupName | ParentGroupID
[tbMemberGrouopRelation] (2M记录):MemberID |的GroupID
组按层次结构排序:
/--- 2
1 --/---- 3 /--- 5
\---- 4 --/---- 6
\---- 7
当我从特定组(及其所有子组)中获取某些成员时,我编写了我的SQL(在SQL Server 2012中):
SELECT m.MemberID, m.MemberName, m.Age, m.Sex
FROM tbMember m
LEFT JOIN tbMemberGroupRelation mg ON (mg.MemberID = m.MemberID)
WHERE mg.GroupID IN (
SELECT GroupID FROM FN_GetAllSubgroups(1)
)
ORDER BY m.MemberID DESC
OFFSET 1000 ROWS FETCH NEXT 40 ROWS ONLY
FN_GetAllSubgroups的实现方式如下:
CREATE FUNCTION [dbo].[GetAllSubgroups] (@parentID int)
RETURNS @t TABLE(GroupID int, ParentID int, GroupName nvarchar(128))
BEGIN
WITH GroupList
AS
(
SELECT GroupID, ParentID, GroupName
FROM dbo.tbGroup
WHERE GroupID = @parentID UNION ALL
SELECT a.GroupID, a.ParentID, a.GroupName
FROM tbGroup a
INNER JOIN GroupList b on a.ParentID = b.GroupID
)
INSERT INTO @t
SELECT a.GroupID, a.ParentID, a.GroupName FROM dbo.tbGroup a
INNER JOIN GroupList b on a.GroupID = b.GroupID
ORDER BY a.ParentID, a.DisplayOrder
RETURN
END
GO
-- index on tbGroup is ParentID (INCLUDE[GroupID, GroupName, DisplayOrder])
函数本身处理速度非常快,即使从顶级节点组中选择(返回10k子组),处理时间也在200ms以内
但是,当我选择从特定子组集合中选择成员的表连接选择时,它变得非常慢(查看我的第一个SQL)。我检查了执行计划,它告诉我{t}的Clurster Index Seek
占用了97%的时间,Estimate rows = 1
和actual rows usually >= 20K
是否有任何解决方案可以加快速度?
非常感谢您的帮助!
======================================
更新:执行结果粘贴在
下面(40行受影响)
表'_tbMember'。扫描计数0,逻辑读取4679267,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
表'_tbMemberGroupRelation'。扫描计数9516,逻辑读取32484,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
表'#AC4BBD06'。扫描计数1,逻辑读取51,物理读取0,预读取读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。
(1行受影响)
SQL Server执行时间:
CPU时间= 2953 ms,经过时间= 9143 ms。
SQL Server解析和编译时间:
CPU时间= 0 ms,经过时间= 0 ms。
SQL Server执行时间:
CPU时间= 0 ms,经过时间= 0 ms。
答案 0 :(得分:1)
您可以尝试将您的功能转换为iTVF
:
CREATE FUNCTION [dbo].[GetAllSubgroups] (
@parentID int
)
RETURNS TABLE
AS
RETURN
WITH GroupList AS (
SELECT
GroupID,
ParentID,
GroupName
FROM dbo.tbGroup
WHERE GroupID = @parentID
UNION ALL
SELECT
a.GroupID,
a.ParentID,
a.GroupName
FROM tbGroup a
INNER JOIN GroupList b
ON a.ParentID = b.GroupID
)
SELECT
a.GroupID,
a.ParentID,
a.GroupName
FROM dbo.tbGroup a
INNER JOIN GroupList b
ON a.GroupID = b.GroupID