优化存储过程

时间:2019-06-19 19:04:00

标签: sql-server tsql stored-procedures query-optimization

我有一个存储过程,该过程被多次调用以获取显示页面所需的所有元素。

样本数据:

CREATE TABLE #temp 
(plan_id INT, parentid INT, label VARCHAR(20),  color VARCHAR(10),  comp_id INT,    start_date DATETIME) 

INSERT INTO #temp 
VALUES
(607, NULL,'abc',   'CDC',  432,    '2018-05-22 00:00:00'),
(607,NULL,'abc',    'CDC',  432,    '2018-05-22 00:00:00'),
(607,NULL,'abc',    'CDC',  433,    '2018-05-22 00:00:00'),  
(NULL,432,'def',    'CDC',  434,    '2018-05-22 00:00:00'),
(NULL,432,'def',    'CDC',  434,    '2018-05-22 00:00:00'),
(NULL,433,'def',    'CDC',  435,    NULL),
(NULL,433,'def',    'CDC',  435,    NULL), 
(NULL,434,'obj',    'CDC',  436,    '2018-05-22 00:00:00'),
(NULL,434,'obj',    'CDC',  436,    '2018-05-22 00:00:00'),
(NULL,435,'obj',    'CDC',  437,    NULL), 
(NULL,436,'ion',    'CDC',  438,    '2018-05-22 00:00:00'),
(NULL,436,'ion',    'CDC',  438,    '2018-05-22 00:00:00'), 
(NULL,437,'ion',    'CDC',  439,    NULL)

存储过程的第一次调用提供一个plan_id(@plan_id)并获取父节点。然后,这些节点在页面代码中循环访问,并随后调用相同的存储过程,但循环中具有元素的comp_id,然后循环中的该元素与另一个调用一起循环以找到其子代。

在具有许多要素的大型计划中,这是非常低效的。 (例如,如果使用@plan_id = 607执行此操作,则将使用comp_id提取父节点;并且在下一个调用中将提供它们,而@plan_id为null)。

DECLARE
@plan_id INT =null,
@parentid INT =null

IF @plan_id is not null 
BEGIN   
SELECT label, color, comp_id, start_date FROM #temp WHERE plan_id = @plan_id 
END 
ELSE 
BEGIN 
SELECT label, color, comp_id, start_date FROM #temp WHERE parentid = @parentid  
END 

即将使用@plan_id = 607和@parentid = null来调用存储过程。 @plan_id = null和@ 432; @plan_id = null和@parentid = 433; @plan_id = null和@parentid = 434; @plan_id = null和@parentid = 435; @plan_id = null和@parentid = 436;和@plan_id = null和@parentid = 437

例如:当@plan_id = 607时,输出为:

我想要做的是,在一个有效的存储过程中构建它,该过程将返回显示页面所需的所有内容。

根据我们的示例,我希望得到如下结果:

SELECT label, color, comp_id, start_date FROM #temp 

它第一次以plan_id = 607执行时,存储过程给出:

label   color   comp_id start_date
abc     CDC     432     2018-05-22 00:00:00.000
abc     CDC     432     2018-05-22 00:00:00.000
abc     CDC     433     2018-05-22 00:00:00.000

然后,将需要432和433来获取parentIds;然后它将使用父ID调用存储过程来执行,并保持计划ID为空。例如,对于parentid = 432,它将返回以下输出:

label   color   comp_id start_date
def     CDC     434     2018-05-22 00:00:00.000
def     CDC     434     2018-05-22 00:00:00.000

该表仅是显示其工作方式和预期输出的示例。

否则,plan_id和parentid是存储过程的参数,结果是在联接多个表并按所需条件进行过滤之后得出的。

任何人都可以帮助我优化此过程,以使单个调用高效地存储过程吗?

1 个答案:

答案 0 :(得分:1)

它看起来像一个简单的递归公用表表达式(CTE):

declare @Samples as Table ( PlanId Int, ParentId Int, Label VarChar(20), Color VarChar(10), CompId Int, StartDate DateTime );
insert into @Samples ( PlanId, ParentId, Label, Color, CompId, StartDate ) values
(607, NULL,'abc',   'CDC',  432,    '2019-05-22 00:00:00'),
(607,NULL,'abc',    'CDC',  432,    '2018-05-22 00:00:00'),
(607,NULL,'abc',    'CDC',  433,    '2018-05-22 00:00:00'),  
(NULL,432,'def',    'CDC',  434,    '2018-05-22 00:00:00'),
(NULL,432,'def',    'CDC',  434,    '2018-05-22 00:00:00'),
(NULL,433,'def',    'CDC',  435,    NULL),
(NULL,433,'def',    'CDC',  435,    NULL), 
(NULL,434,'obj',    'CDC',  436,    '2018-05-22 00:00:00'),
(NULL,434,'obj',    'CDC',  436,    '2018-05-22 00:00:00'),
(NULL,435,'obj',    'CDC',  437,    NULL), 
(NULL,436,'ion',    'CDC',  438,    '2018-05-22 00:00:00'),
(NULL,436,'ion',    'CDC',  438,    '2018-05-22 00:00:00'), 
(NULL,437,'ion',    'CDC',  439,    NULL);

select * from @Samples;

with Things as (
  -- Get all of the plans ...
  select PlanId, ParentId, Label, Color, CompId, StartDate
    from @Samples
    where ParentId is NULL
  union all
  -- ... add the children one level at a time.
  select S.PlanId, S.ParentId, S.Label, S.Color, S.CompId, S.StartDate
    from Things as T inner join @Samples as S on T.CompId = S.ParentId
  )
  select PlanId, ParentId, Label, Color, CompId, StartDate
    from Things;