Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 具有高扫描计数和逻辑读取的递归CTE_Sql_Sql Server_Tsql_Sql Server 2012_Query Performance - Fatal编程技术网

Sql 具有高扫描计数和逻辑读取的递归CTE

Sql 具有高扫描计数和逻辑读取的递归CTE,sql,sql-server,tsql,sql-server-2012,query-performance,Sql,Sql Server,Tsql,Sql Server 2012,Query Performance,我试图在递归CTE下进行优化,但运气不佳。该表有5079条记录 ;WITH CTE_REC AS ( SELECT ID , ParentId , ID as ChildId , IsActive FROM #temp UNION ALL SELECT C.ID , C.ParentId

我试图在递归CTE下进行优化,但运气不佳。该表有5079条记录

;WITH CTE_REC AS (

     SELECT         
          ID
        , ParentId
        , ID as ChildId
        , IsActive          
        FROM
        #temp

    UNION ALL


    SELECT 
         C.ID
        , C.ParentId    
        , H.ChildId 
        ,H.IsActive         
    FROM 
        #temp AS C
        INNER JOIN
        CTE_REC H ON C.ID = H.ParentId  
)
SELECT * FROM CTE_REC
上述查询的执行计划为:

IO统计数据包括:

(25441 row(s) affected)
Table 'Worktable'.
Scan count 20365, logical reads 193768, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical reads 0,
lob read-ahead reads 0.
Table '#temp_______________________________________________________________________________________________________________000000001B2D'.
Scan count 2, logical reads 34, physical reads 0, read-ahead reads 17,
lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
我在临时表上创建了以下索引

CREATE INDEX IX_TEMP ON #Temp(Id,ParentId)
创建索引后,执行计划如下所示

索引后的IO统计信息:

Table '#temp_______________________________________________________________________________________________________________000000001B2D'.
Scan count 20364, logical reads 40776, physical reads 0, read-ahead reads 0,
lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'.
Scan count 2, logical reads 142778, physical reads 0, read-ahead reads 0,
lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

索引之后仍然存在高扫描计数和逻辑读取。CTE返回25411行,我没有发现CPU时间有任何差异,即400毫秒(带索引/不带索引)。

您是否尝试在临时表上创建聚集索引。您创建的索引是非聚集索引,这意味着您的临时表仍然是一个堆,因此扫描计数很高,因为查询将在堆中进行扫描,以查找ChildID、IsActive等的键

在临时表上的ID、ParentID上创建聚集索引(创建聚集索引)。
然后为ParentID、ID、ChildID和IsActive添加覆盖非聚集索引。您可能需要测试此NCI,因为最好将ID移到末尾。

对于服务器来说,递归只是很多步骤

我会在ID上放一个聚集的PK

在ParentID到ID之间放置FK可能会有帮助,而且可能会造成伤害

在锚点中,您可以将ParentId不为null的位置放入
,但它们不会太多,这将从报告中删除它们

在锚中,您可以只过滤到没有人向其报告的人。你仍然拥有所有的锁链。当我的老板和我的老板是同一条链子的时候,我的老板却有一条单独的链子,这有点傻

计算桥墩的链条也是一种浪费。如果我们有一个共同的老板,那么我们有相同的链条。这里3和6具有相同的链。在我下面的示例中,您只需关注:

select min(e.id) as 'modelGrunt', e.mgr
  from @emp e  
 where not exists (select 1 from @emp e1 where e1.mgr = e.id)
 group by e.mgr;
根据这些信息,您可以构建每条链。运行并实现它。这是一个更复杂的查询,但将递归行数减少到接近最小值。这不是一个完整的最低限度,因为你可能会发疯,甚至不会重复子链

我有几乎相同的,但在小计数这不是一个问题。您需要使用排序进行优化,否则结果不会以有意义的方式分组。它有一个索引搜索和一个索引扫描

declare @emp table (id  int primary key, mgr int);  
insert into @emp values 
       (1, null)
     , (2, 1)
     , (3, 2)
     , (4, null)
     , (5, 4) 
     , (6, 2);
--select * from @emp;

; with cte as 
( select e.id ori, e.id, e.mgr, cnt = 1 
    from @emp e  
  union all 
  select cte.ori,  e.id, e.mgr, cnt + 1
    from @emp e 
    join cte 
      on cte.mgr = e.id 
) 

 select ori, id, mgr, cnt  
 from cte  
 order by ori, cnt;

您的定位不太正确,您需要将顶层限制为非子项的行:

;WITH CTE_REC AS (
     SELECT         
          ID
        , ParentId
        , ID as ChildId
        , IsActive          
        FROM #temp
        WHERE ParentId IS NULL
    UNION ALL
    SELECT 
         C.ID
        , C.ParentId    
        , H.ChildId 
        ,H.IsActive         
    FROM #temp AS C
    INNER JOIN CTE_REC H 
       ON C.ID = H.ParentId  
    WHERE C.ParentId IS NOT NULL
)
SELECT * FROM CTE_REC

你应该减少锚的行数。在ParentId不为NULL的位置添加
可能是一个不错的选择,但这实际上取决于您的数据和您需要的内容。为什么不使用
hierarchyid
而不是递归?我不知道hierarchyid。你能给我一些关于hierarchyid的链接吗?看起来你的查询是错误的。非常高的Cardianity估计值。你应该改进你的锚定和递归。奇怪的格式。你聚集在什么上?身份证件你还在使用你创建的NCI吗?尝试为ParentID、ID、ChildID、IsActive添加NCI,而不是上面描述的NCI否。我删除了NCI并创建了ID为ParentID的CI。没有用。它们不多,而且处理速度很快。问题是他们没有被直接报道。@狗仔队不确定我是否理解这个评论。请提供一些样本数据。不将锚点仅限于parentid为null的行的问题是,您将多次报告相同的行。e、 g.如果A->B->C,你将报告这个,B->C和C。我不同意。我在答复中公布了数据。如果添加空值,则会得到不同的报告。如果要修剪链条,这只会修剪链条的顶部。我没有投你反对票。我认为这是有效的输入。@狗仔队您的加入是不正确的。如果您使用“on cte.id=e.mgr”作为加入条件,那么您可以添加where。。不要为你的锚定为null,然后锚定得到正确的报告。在您的查询中,id 2会被报告两次。我不想和您争论。我已经运行了查询。