这里我有一个存储过程似乎比我希望的运行时间更长一些。使这个算法如此冗长的原因是在SQL中将一个元素添加到一个新表时,它似乎并不总是放在最顶层。
我还必须查询创建另一个表的查询。总而言之,这个算法太大了。有没有人想让它变短?
DECLARE @RecipeQuery TABLE(
RecipeID NCHAR(100),
MaterialID NCHAR(100),
Quantity DECIMAL(18,4));
INSERT INTO @RecipeQuery
(RecipeID, MaterialID, Quantity)
SELECT RecipeID, MaterialID, Quantity
FROM Recipe
DECLARE @PrevRecipeQuery TABLE(
prevRecipeID NCHAR(100),
prevMaterialID NCHAR(100),
prevQuantity DECIMAL(18,4));
DECLARE @TempRecipeQuery TABLE(
TempRecipeID NCHAR(100),
TempMaterialID NCHAR(100),
TempQuantity DECIMAL(18,4));
DECLARE @MaterialFinder TABLE(
RID NCHAR(100),
MID NCHAR(100),
Q DECIMAL(18,4));
DECLARE @PrevMaterialFinder TABLE(
PRID NCHAR(100),
PMID NCHAR(100),
PQ DECIMAL(18,4));
DECLARE @CalcMaterial TABLE(
CalcRecipeID NCHAR(100),
CalcMaterialID NCHAR(100),
CalcQuantity DECIMAL(18,4));
DECLARE @ROWCOUNT1 INT
SET @ROWCOUNT1 = 0
DECLARE @ROWCOUNT2 INT
SET @ROWCOUNT2 = 0
DECLARE @ROWCOUNT3 INT
SET @ROWCOUNT3 = 0
DECLARE @isDone INT
SET @isDone = 0
DECLARE @mainRowCount INT
--------------------------------------------------------------------------------------------------
--LOOP UNTIL ALL LEVELS HAVE BEEN FOUND
WHILE(@isDone != 1)
BEGIN
SET @mainRowCount = (SELECT COUNT(*) FROM @RecipeQuery)
--LOOP THROUGH EACH ROW IN THE TABLE UNTIL ALL ROWS HAVE BEEN LOOKED AT
WHILE(@ROWCOUNT1 < @mainRowCount)
BEGIN
--IF THE ROW'S MATERIAL STARTS WITH A "TempRecipeID" THAT MEANS IT IS DONE
IF(PATINDEX('R%', (SELECT TOP 1 MaterialID FROM @RecipeQuery)) = 1)
BEGIN
--INSERT THE ROW RIGHT INTO TABLE new
INSERT INTO @CalcMaterial (CalcRecipeID, CalcMaterialID, CalcQuantity) SELECT TOP 1 RecipeID, MaterialID, Quantity FROM @RecipeQuery
SET @ROWCOUNT3 = @ROWCOUNT3 + 1
END
--OTHERWISE
ELSE
BEGIN
--FIND THE MATERIAL'S RECIPE AND PLACE THE NEW RECIPEID AND MATERIALID INTO TABLE TempMaterialID
INSERT INTO @PrevMaterialFinder (PRID, PMID, PQ) SELECT TOP(1) RecipeID, MaterialID, Quantity FROM @RecipeQuery
INSERT INTO @MaterialFinder (RID, MID, Q) SELECT (SELECT TOP 1 RecipeID FROM @RecipeQuery), MaterialID, Quantity FROM Recipe WHERE RecipeID = (SELECT TOP 1 MaterialID FROM @RecipeQuery)
DECLARE @ROWCOUNT4 INT
SET @ROWCOUNT4 = (SELECT COUNT(*) FROM @MaterialFinder)
WHILE(@ROWCOUNT2 < @ROWCOUNT4)
BEGIN
INSERT INTO @CalcMaterial
(CalcRecipeID, CalcMaterialID, CalcQuantity)
SELECT TOP 1 RID, MID, Q*(SELECT TOP 1 PQ FROM @PrevMaterialFinder)*0.001
FROM @MaterialFinder
DELETE TOP(1) FROM @MaterialFinder
SET @ROWCOUNT2 = @ROWCOUNT2 + 1
END
SET @ROWCOUNT2 = 0
END
SET @ROWCOUNT2 = 0
--DELETE THE TOP ROW
DELETE TOP(1)
FROM @RecipeQuery
--INSERT THE UPDATED ROW(S) FROM TABLE TempMaterialID INTO TABLE W
INSERT INTO @TempRecipeQuery
(TempRecipeID, TempMaterialID, TempQuantity)
SELECT CalcRecipeID, CalcMaterialID, CalcQuantity
FROM @CalcMaterial
--DELETE THE UPDATED ROWS FROM TABLE TempMaterialID
DELETE FROM @MaterialFinder
DELETE FROM @PrevMaterialFinder
DELETE FROM @CalcMaterial
--INCREASE ROW COUNTER C
SET @ROWCOUNT1 = @ROWCOUNT1 + 1
--LOOP ONTO NEXT ROW
END
--AT THIS POINT ALL OF THE ROWS HAVE BEEN GONE THROUGH AT LEAST ONCE
--INSERT THE UPDATED ROWS IN TABLE W INTO THE MAIN TABLE
INSERT INTO @RecipeQuery
(RecipeID, MaterialID, Quantity)
SELECT TempRecipeID, TempMaterialID, TempQuantity
FROM @TempRecipeQuery
--TO COMPARE
--IF THE COUNT OF BOTH TABLES IS THE SAME THEY COULD BE THE SAME
IF((SELECT COUNT(*) FROM @prevRecipeQuery) = (SELECT COUNT(*) FROM @RecipeQuery))
BEGIN
--IF THE DIFFERENCES BETWEEN THE TWO ARE NULL THEN THEY ARE THE SAME;
IF(SELECT MaterialID FROM @RecipeQuery EXCEPT SELECT prevMaterialID FROM @prevRecipeQuery) IS NULL
--SET DONE TO 1 TO END LOOP
SET @isDone = 1
END
--DELETE PREV TABLE FOR NEW UPDATE
DELETE FROM @prevRecipeQuery
--SET COPY INTO PREV
INSERT INTO @prevRecipeQuery
(prevRecipeID, prevMaterialID, prevQuantity)
SELECT RecipeID, MaterialID, Quantity
FROM @RecipeQuery
--SET THE ROW COUNTER BACK TO 0
SET @ROWCOUNT1 = 0
--DELETE ALL FROM THE TEMP UPDATED TABLE SO THAT IT CAN BE FILLED WITH UPDATED ROWS IF AGAIN
DELETE FROM @TempRecipeQuery
--AT THIS POINT THE LOOP WILL REPEAT IF THERE ARE ANY MORE STOCK SOLUTIONS AS MATERIALS
END
--AT THIS POINT, ALL LOOPS ARE DONE AND THE MAIN TABLE DOES NOT CONSIST OF ANY STOCK MATERIALS AS MATERIALS
--PRINT THE MAIN TABLE
SELECT RecipeID, MaterialID, Quantity FROM @RecipeQuery
ORDER BY RecipeID
输入是食谱表 输出是输出所需表, 您可以看到添加的行为黄色,因为查询会查询自己以查找每个配方中的材料。
请注意,只有列和第3行必须出现在最终查询中。我添加了这些以显示如何生成3级。
INPUT:
食谱材料
aa01 B1
aa01 B2
aa01 bb01
bb01 B1
bb01 cc01
cc01 B3
cc01 B4
B1 B1
B2 B2
B3 B3
B4 B4
输出:
食谱材料
aa01 B1
aa01 B2
aa01 B1
aa01 B3
aa01 B4
bb01 B1
bb01 B3
bb01 B4
cc01 B3
cc01 B4
B1 B1
B2 B2
B3 B3
B4 B4
答案 0 :(得分:1)
我的故事是关于如何改善SP中while循环的性能:
我遇到了同样的问题,即while循环的性能缓慢,几乎有五十万行。我使用表变量循环并使用标识列作为迭代器。太慢了。后来我将table变量更改为本地临时表,并根据循环内的select命令创建了一些索引。从30分钟的早期开始,总时间急剧减少到2-3分钟。 如果您还有那么多行,请尝试使用具有适当索引的临时表。
简而言之:尝试使用具有适当索引的临时表替换表变量。