优化存储过程
Posted
技术标签:
【中文标题】优化存储过程【英文标题】:Optimize a stored procedure 【发布时间】:2019-06-19 19:04:00 【问题描述】:我有一个存储过程,它被多次调用以获取显示页面所需的所有元素。
样本数据:
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 为空)。
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是存储过程的参数,结果是连接多张表并根据需要的条件过滤后的结果。
谁能帮我优化一下,从而使单次调用高效的存储过程?
【问题讨论】:
为什么不直接WHERE plan_id = @plan_id OR parentid = @parentid
?
我已经把它作为一个例子。一旦提供了 plan_id,它就会从 comp_id 中获取 parentid。它保留它们,生成 parentid,然后使用它来执行存储过程。
@lije,我没有验证脚本..在我看来..您是否尝试过接受参数并在连接查询或选择查询中工作的表值函数..
@goofyui,好的,我会检查一下。但是如果有机会,请尝试使用脚本查看。谢谢!
您希望根据您提供的样本数据生成什么输出?请记住 - 我们在这方面的工作不如您,所以对您来说显而易见的事情对我们来说并不明显。
【参考方案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;
【讨论】:
但问题是,输出没有 planId 和 parentid 列。我把它们放在一起是为了提供一个很好的例子。不过还是谢谢。 @lije 您可以从最后的select
中省略PlanId
和ParentId
列。
我已编辑问题以提供几个示例表/输出。你能看看吗?我没有按原样的@sample 表;我的意思是给出整个数据集的想法。我根据传递的参数检索了它。因此,我什至无法在 CTE 中按 parentid 进行选择和过滤。以上是关于优化存储过程的主要内容,如果未能解决你的问题,请参考以下文章