Mysql хранимая процедура для обновления и возврата списка совпадающих строк - PullRequest
0 голосов
/ 22 сентября 2018

Я построил эту хранимую процедуру.Предполагается выбрать все незапущенные строки из таблицы, которую мы используем в качестве очереди.Обновите эти строки, чтобы пометить их как «STARTING», чтобы они не были захвачены другим процессором, а затем верните эти строки обратно запрашивающей стороне для обработки.Это работает, но, кажется, создает неприемлемо высокую нагрузку на наши серверы.

Основная причина этой хранимой процедуры - выбор и обновление строк, чтобы мы не получали одну и ту же строку, выбранную несколькими процессорами вв то же время.

Я не администратор баз данных, и мне пришлось на лету изучать некоторые хранимые процедуры и курсоры, поэтому, возможно, я упускаю что-то очевидное для кого-то другого.Я предполагаю, что есть способ сделать это без полной перегрузки наших серверов БД.Любая помощь приветствуется.

Мы используем 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 голосов
/ 22 сентября 2018

Это работает, но, кажется, создает неприемлемо высокую нагрузку на наши серверы.

В качестве 2 первых шагов,

  1. Возможно,полезно иметь «индексы» в столбцах: status и companyid.Если у вас нет индексов, вы можете создать их, используя:

    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 ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...