MySQL Хранимая процедура завершается с ошибкой с кодом 2013 (потеря соединения с MySQL сервером во время запроса) - PullRequest
0 голосов
/ 13 апреля 2020

Заранее спасибо за попытку помочь мне!

Моя проблема заключается в следующем: у меня есть хранимая процедура fill_enrollment_id (). Эта процедура объявляет курсор, данные которого заполняют некоторые переменные, которые впоследствии используются для инструкции SELECT INTO для заполнения другой переменной (v_enrollmentid). Затем процедура проверяет, возвращает ли инструкция SELECT INTO исключение NOT FOUND. Если действительно возникает исключение NOT FOUND, то процедура выполняет ОБНОВЛЕНИЕ для столбца "enrollmentid" таблицы "mdl_edulevel2_log" со значением по умолчанию "0 - 0"; и затем обновляет переменную обработчика NOT FOUND, чтобы курсор мог выполнять итерации. В противном случае, если исключение не вызывается, процедура выполняет предложение UPDATE со значением, полученным с помощью инструкции SELECT INTO. Наконец, устанавливаются инструкции для закрытия курсора и выхода из l oop. Код процедуры выглядит следующим образом:

CREATE DEFINER=`mutual`@`%` PROCEDURE `fill_enrollment_id`()
BEGIN

    DECLARE v_id BIGINT DEFAULT 0;
    DECLARE v_userid BIGINT DEFAULT 0;
    DECLARE v_courseid BIGINT DEFAULT 0;
    DECLARE v_timecreated BIGINT DEFAULT 0;
    DECLARE v_enrollmentid VARCHAR(255) DEFAULT null;
    DECLARE exit_loop BOOLEAN;
    DECLARE edulog_cursor CURSOR FOR SELECT id, userid, courseid, timecreated FROM mdl_edulevel2_log WHERE userid not in (0, 2, 3);
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET exit_loop = TRUE;

    OPEN edulog_cursor;
    edulog_loop: LOOP
        FETCH edulog_cursor INTO v_id, v_userid, v_courseid, v_timecreated;

        SELECT ifnull(enrollmentid, "0 - 0")
        INTO v_enrollmentid
        FROM mdl_enrollments
        WHERE m_relateduserid = v_userid
        AND m_courseid = v_courseid
        AND ((v_timecreated >= m_timecreated) AND (v_timecreated <= dm_timecreated OR dm_timecreated = 0));

        IF exit_loop THEN 

            UPDATE mdl_edulevel2_log
            SET enrollmentid = "0 - 0"
            WHERE id = v_id;
            SET exit_loop = FALSE;

        ELSE

            UPDATE mdl_edulevel2_log
            SET enrollmentid = v_enrollmentid
            WHERE id = v_id;

        END IF;

        IF exit_loop THEN
            CLOSE edulog_cursor;
            LEAVE edulog_loop;
        END IF;
    END LOOP edulog_loop;

END

Мне кажется, что logi c в порядке, но процедура завершается с ошибкой Код ошибки 2013. Потерянное соединение с MySQL сервером во время запроса . Я действительно не знаю, почему это происходит. Моя интуиция говорит, что это связано с размером запроса курсора (143,115 строк) и тем фактом, что я запускаю это локально на моем ноутбуке (Intel® Core), i5 M250, 2,4 ГГц, 8 ГБ ОЗУ и 64 бита Windows 10 Pro). С другой стороны, интервал ожидания установлен на 600 в MySQL Workbench (см. Изображение ниже). Я не уверен, что увеличение этого значения решит проблему или усугубит ее.

MySQL Workbench SQL Editor's Preferences

Наконец, я поделюсь с вами определением Обе таблицы используются в процедуре (mdl_edulevel2_log и mdl_enrollments), поэтому вы можете видеть, что надлежащие индексы определены, поэтому процедура выполняется быстрее. Вот они:

CREATE TABLE `mdl_edulevel2_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `eventname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `component` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `action` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `target` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `objecttable` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `objectid` bigint DEFAULT NULL,
  `crud` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
  `edulevel` tinyint(1) NOT NULL,
  `contextid` bigint NOT NULL,
  `contextlevel` bigint NOT NULL,
  `contextinstanceid` bigint NOT NULL,
  `userid` bigint NOT NULL,
  `courseid` bigint DEFAULT NULL,
  `relateduserid` bigint DEFAULT NULL,
  `anonymous` tinyint(1) NOT NULL DEFAULT '0',
  `other` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
  `timecreated` bigint NOT NULL,
  `origin` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `realuserid` bigint DEFAULT NULL,
  `enrollmentid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `mdl_edulevel2log_tim_ix` (`timecreated`),
  KEY `mdl_edulevel2log_couanotim_ix` (`courseid`,`anonymous`,`timecreated`),
  KEY `mdl_edulevel2log_useconconcr_ix` (`userid`,`contextlevel`,`contextinstanceid`,`crud`,`edulevel`,`timecreated`),
  KEY `mdl_edulevel2log_con_ix` (`contextid`),
  KEY `idx_mdl_edulevel2_log_userid` (`userid`)
) ENGINE=InnoDB AUTO_INCREMENT=4727019 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Standard log table';

CREATE TABLE `mdl_enrollments` (
  `m_id` bigint NOT NULL,
  `m_objectid` bigint DEFAULT NULL,
  `m_userid` bigint NOT NULL,
  `m_courseid` bigint DEFAULT NULL,
  `m_relateduserid` bigint DEFAULT NULL,
  `m_timecreated` bigint NOT NULL,
  `m_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `dm_id` bigint DEFAULT NULL,
  `dm_objectid` bigint DEFAULT NULL,
  `dm_userid` bigint DEFAULT NULL,
  `dm_courseid` bigint DEFAULT NULL,
  `dm_relateduserid` bigint DEFAULT NULL,
  `dm_timecreated` bigint DEFAULT NULL,
  `dm_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `enrollmentid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`enrollmentid`),
  KEY `idx_mdl_enrollments_m_relateduserid` (`m_relateduserid`),
  KEY `idx_mdl_enrollments_m_courseid` (`m_courseid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Standard log table';

Но, если честно, я не совсем уверен, что эти индексы используются. Я не знаю, чтобы сделать оператор EXPLAIN для вызова хранимой процедуры. Но когда я делал оператор EXPLAIN для запросов по отдельности, в них были результаты:

Explain Statement for First Query in the Procedure

Explain Statement for Second Query in the Procedure

Explain Statement for Update Sentence in the Procedure

Итак, похоже, что индексы могут быть использованы, но, как я уже говорил, я не совсем уверен, что после вызова процедуры используются индексы.

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

Привет из Венесуэлы и извините, если мой английский sh не достаточно ясен.

1 Ответ

1 голос
/ 13 апреля 2020

Во-первых, вы сериализуете запрос, который вам не нужен. Курсор с 143115 строками вызывает 1 выбор и 1 обновление для каждой строки, что приводит к 143115 * 2 + 1 = 286231 SQL операциям. Это займет так много времени, что ваш тайм-аут выполнения (ошибка 2013).

Во-вторых, ваш курсор logi c, кажется, не работает. Когда курсор l oop заканчивается (больше строк не обрабатывается), он превращает переменную exit_loop в true. Тем не менее, вы пытаетесь выполнить последнее обновление и повернуть exit_loop обратно на false, как будто курсор должен продолжаться.

Вы, вероятно, можете сделать то же самое с одной операцией SQL, где у вас есть все логи c:

UPDATE mdl_edulevel2_log l
  INNER JOIN mdl_enrollments e ON e.m_relateduserid = l.userid 
     AND ((l.timecreated >= e.m_timecreated) 
          AND (l.timecreated <= e.dm_timecreated OR e.dm_timecreated = 0)
         )
SET enrollmentid = ifnull(e.enrollmentid, "0 - 0")
WHERE l.userid not in (0, 2, 3);
...