mysql - 如何加速mysql中的存储过程

标签 mysql stored-procedures

下面给出的是我的程序执行时间太长。

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 时间。如果有人指导我如何减少执行时间?

提前谢谢你。

最佳答案

您可以使用单个 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 中,我使用了两个过程变量 IsRankSkiptestid1

备注

如果你总是为所有的 testid 值调用你的过程,那么上面的内容可以进一步改进,所以所有这些更新只用一个 update 语句完成。

关于mysql - 如何加速mysql中的存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38519454/

相关文章:

php - 如何清除 15 分钟或更早的 MySQL 记录?

php - 面向对象的 MySQL 语句,PHP

PHP 未将数组插入 MySQL 数据库

php - 使用join语句从两个表中删除,但出现错误

sql - 如何在SQL Server中更好地复制一组数据

sql - 动态 sql 与存储过程 - 优缺点?

sql-server - Sql Server - 避免延迟编译

php - 将数据从可变数量的表格插入mysql到相应的列

MySQL 过程无法识别参数

表变量的 MySQL 存储过程语法错误