1

在我的项目中,我遇到了以下 T-SQL 代码的挑战。

  1. step1 使用父模块及其订阅用户填充 UserModules 表
  2. step2 在 Modules_Hierarchy 表中检查与 step1 中的模块关联的子模块,并通过将子模块与父模块订阅的用户映射来将有效记录插入到 UserModules 表中。此步骤将递归重复,直到找到所有子模块。

问题:

在第 2 步中,WHILE 循环和 SELECT 语句使用相关子查询,并且表 UserModules 是 INSERT 和相关 SELECT 子句的一部分,这会妨碍性能,并且查询经常会因以下 LOCK 升级问题而失败。

ModulesUsers 表中的最终数据大小为 4200 万,预计还会增长。

错误消息: “SQL Server 数据库引擎的实例此时无法获取 LOCK 资源。当活动用户较少时重新运行您的语句。请数据库管理员检查此实例的锁和内存配置,或检查长时间运行的事务。”</p>

如何优化此查询,即第 2 步以解决问题?

第1步:

INSERT INTO UserModules(ModuleID, UserID)
  SELECT ModuleID, UserID
  FROM TABLEA a
  INNER JOIN TABLEB b ON a.ID = b.ID

第2步:

DECLARE @cnt int
SET @cnt = 1

WHILE( @cnt > 0 )      
BEGIN      

  SET @cnt = (SELECT COUNT(DISTINCT s.moduleid)
              FROM Modules_Hirarchy s WITH (nolock), Modules t      
              WHERE s.ParentModuleId = t.ModuleId      
              ------------      
                AND NOT EXISTS       
                 (SELECT ModuleId + EndUserId 
                  FROM UserModules  r      
                  WHERE s.moduleid = r.moduleid 
                    AND t.EndUserId = r.EndUserId)
                AND s.moduleid + t.EndUserId NOT IN 
                  (SELECT CAST(ModuleId AS varchar) + EndUserId 
                   FROM UserModules ))      

  IF @cnt = 0      
    BREAK      

  INSERT INTO UserModules (ModuleId, EndUserId)      
    SELECT DISTINCT s.moduleid, t.EndUserId       
    FROM Modules_Hirarchy s WITH (nolock), UserModules  t      
    WHERE s.ParentModuleId = t.ModuleId      
      AND NOT EXISTS       
       (SELECT ModuleId + EndUserId 
        FROM UserModules  r      
        WHERE s.moduleid = r.moduleid 
          AND t.EndUserId = r.EndUserId)

END  
4

1 回答 1

0

一些数据可以玩

create table #UserModules(ModuleID int, UserID int)

create table #Modules_Hirarchy(ParentModuleID int, ChildModuleID int)

insert into #UserModules (ModuleID , UserID)
values(1,1)
,(2,1)
,(3,1)
,(4,1)
,(5,1)
,(6,2)
,(7,2)

insert into #Modules_Hirarchy(ParentModuleID , ChildModuleID )
values (null,1)
,(1,2)
,(2,3)
,(3,4)
,(3,5)
,(null,6)
,(6,7)

解析度

with cts(ModuleID, UserID,parentModule ) as 
(
select a.ModuleID, a.UserID , CAST(null as int)as parentModule --, cAST(null as int)as b
from #UserModules a join #Modules_Hirarchy  b on a.ModuleID = b.ChildModuleID 
where b.ParentModuleID is null

union all

select b.ChildModuleID as ModuleID, a.UserID, b.ParentModuleID
from cts a join #Modules_Hirarchy b 
on a.ModuleID = b.ParentModuleID

)
select *
into #RESULT
from cts

编辑它很难说 :) 到许多变量,但你应该做的事情是使查询高效

  1. 列上的单独非聚集索引ModuleID ParentModuleID ChildModuleID

  2. 您可能不想查询所有组,而只想查询显式组,在锚语句中过滤掉尽可能多的组

    选择 a.ModuleID, a.UserID , CAST(null as int) as parentModule from #UserModules a join #Module_Hirarchy b on a.ModuleID = b.ChildModuleID 其中 b.ParentModuleID 为 null 且 a.ModuleId in (listOfModules)

  3. 为列添加唯一索引(ParentModuleID, ChildModuleID)作为非唯一行可能会导致大量行重复

除了它依赖于 ParentModuleID ChildModuleID 上的数据选择性,但你对此无能为力

我认为它适用于大数据集,因为谓词很简单并且只要数据选择性很高

于 2013-01-22T15:18:17.470 回答