MySQL存储过程可更新并返回匹配行的列表

时间:2018-09-22 19:52:59

标签: mysql sql stored-procedures

我建立了这个存储过程。应该从我们用作队列的表中选择所有“非开始”行。更新这些行以将其标记为“开始”,这样它们就不会被其他处理器抓取,然后将这些行返回给请求者进行处理。它可以工作,但是似乎给我们的服务器带来了不可接受的高负载。

此存储过程的主要原因是选择并更新行,这样我们就不会同时获得由多个处理器选择的同一行。

我不是DBA,所以我必须动态学习一些存储过程和游标,所以也许我错过了其他人显而易见的东西。我猜想有一种方法可以在不完全过载数据库服务器的情况下执行此操作。任何帮助表示赞赏。

我们将MySql db 5.6.xx与Java / Tomcat网络应用程序配合使用。

CREATE DEFINER=`admin`@`%` PROCEDURE `select_and_start_non_started`(
    IN p_companyId INT(11),
    IN p_howMany INT, 
    IN p_instance varchar(50),
    IN p_status varchar(50), 
    IN p_updateBy varchar(50)
)
BEGIN


    DECLARE  v_currentId        INT;
    DECLARE  v_loopDone         INT DEFAULT 0;
    DECLARE  v_loopCounter      INT DEFAULT 0;
    DECLARE  v_idList           VARCHAR(1024) DEFAULT NULL;

    DECLARE queue_csr CURSOR FOR 
        SELECT id FROM queue 
            WHERE (status in (_utf8'NEW' COLLATE utf8_unicode_ci, 
                              _utf8'RESTARTED' COLLATE utf8_unicode_ci, 
                              _utf8'WAITING' COLLATE utf8_unicode_ci, 
                              _utf8'QUEUED' COLLATE utf8_unicode_ci)) 
              AND if(LENGTH(p_companyId) > 0, companyid=p_companyId, true)                       
         LIMIT p_howMany FOR UPDATE;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_loopDone=1;
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
    BEGIN
        ROLLBACK;
        SET autocommit = TRUE;
        RESIGNAL;
    END;

    SET v_idList = "";

    SET autocommit = FALSE;
    START TRANSACTION;

    OPEN queue_csr;
    iq_loop:LOOP
        FETCH queue_csr INTO v_currentId;
        IF v_loopDone THEN LEAVE iq_loop; END IF;


        UPDATE queue SET status = p_status COLLATE utf8_unicode_ci, updatedDate=NOW(), updatedBy=p_updateBy, recordStatus=p_instance WHERE id = v_currentId;
        SET v_idList = CONCAT(v_idList, ",", v_currentId);
        SET v_loopCounter=v_loopCounter+1;
        IF v_loopCounter > p_howMany THEN LEAVE iq_loop; END IF;

    END LOOP iq_loop;
    CLOSE queue_csr;
    SET v_loopDone=0;

    COMMIT;
    SET autocommit = TRUE;

    SELECT * FROM queue q WHERE FIND_IN_SET(id, v_idList);

END

1 个答案:

答案 0 :(得分:2)

它可以工作,但似乎给我们的服务器带来了不可接受的高负载。

作为2个第一步,

  1. 在以下列上包含“索引”可能会有所帮助:状态和 公司编号。如果没有索引,可以使用以下方法创建它们:

    alter table select_and_start_non_started add index (status);
    alter table select_and_start_non_started add index(companyid);
    
  2. p_companyId是一个整数,所以我不确定为什么要使用它的长度。无论如何,由于LENGTH(p_companyId)是一个常量,因此您不必将其保存在变量中:


declare v_companyid_len int;
set v_companyid_len=LENGTH(p_companyId);
BEGIN
DECLARE queue_csr CURSOR FOR .... AND if(v_companyid_len>0 ...