下面给出的是我的程序需要花费太多时间才能执行。
BEGIN
DECLARE rank1 BIGINT DEFAULT 0;
DECLARE id1 BIGINT;
DECLARE rankskip BIGINT DEFAULT 0;
DECLARE mark DECIMAL(10,2) DEFAULT 0;
DECLARE oldmark DECIMAL(10,2) DEFAULT -100000;
DECLARE done int DEFAULT 0;
DECLARE cursor_i CURSOR FOR
SELECT
(rightmarks - negativemarks) as mark, id
FROM
testresult
WHERE
testid = testid1
ORDER BY
(rightmarks - negativemarks) DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cursor_i;
read_loop: LOOP
FETCH cursor_i INTO mark, id1;
IF done = 1 THEN
LEAVE read_loop;
END IF;
IF oldmark = mark THEN
BEGIN
IF IsRankSkip = 1 THEN
BEGIN
SET rankskip = rankskip + 1;
END;
END IF;
END;
ELSE
BEGIN
SET rank1 = rank1 + rankskip + 1;
SET rankskip = 0;
END;
END IF;
SET oldmark = mark;
UPDATE testresult SET rank = rank1 WHERE id=id1;
END LOOP;
CLOSE cursor_i;
END
此循环至少迭代2000次。
这里IsRankSkip和testid1是传递给过程的参数。
此过程需要65.343152046204的时间来执行。如果有人指导我如何减少执行时间?
提前谢谢。
答案 0 :(得分:0)
您可以使用单个update
语句执行此操作,并使用在执行期间更改的变量:
UPDATE testresult a
JOIN ( SELECT id,
@row := @row + 1 row_number,
@rank := if(mark = @lastmark, @rank, @row) as rank,
@dense_rank := @dense_rank + if(mark = @lastmark, 0, 1) as dense_rank,
@lastmark := mark as mark
FROM ( SELECT rightmarks - negativemarks as mark,
id
FROM testresult
WHERE testid = testid1
ORDER BY 1 DESC
) data,
(SELECT @row := 0, @dense_rank := 0) r
) b
ON a.id = b.id
SET a.rank = if(IsRankSkip, b.rank, b.dense_rank);
带别名b
的查询计算排名,并将其添加为结果集中的列。实际上,它增加了三种数字:
@row
:没有特殊处理等值的连续行号@rank
:与值的行号相同,与前一个值不同,否则与上一行相同@dense_rank
:当值与之前的值不同时,此值会递增,否则会与上一行中的值相同您可以选择使用哪个更新排名列。在上面的SQL中,我使用了两个过程变量 IsRankSkip 和 testid1 。
如果您总是为所有 testid 值调用您的过程,则可以进一步改进上述内容,因此所有这些更新仅使用一个update
语句完成。