2015-05-06 5 views
1

То, что я пытаюсь сделать, это написать хранимую процедуру, которая будет запрашивать представление, обрабатывать каждую строку и делать одну или несколько вставок в таблицу для каждой строки, вытащенной из представления. Все кажется прекрасным, за исключением того факта, что во время процесса произвольно, в середине точки, сервер, похоже, висеть на команде вставки. Я понятия не имею, есть ли ограничение памяти на наборах результатов курсора или что может произойти. Соответствующие части SP и несколько поясняющих комментариев, размещенных ниже.MySQL Хранимая процедура Вставка Висячие

CREATE PROCEDURE `Cache_Network_Observations`() 
BEGIN 

-- Declare all variables 

/* This cursor is hitting the view which should be returning a number of rows on the scale of ~5M+ records 
*/ 
DECLARE cursor1 CURSOR FOR 
SELECT * FROM usanpn2.vw_Network_Observation; 

CREATE TABLE Cached_Network_Observation_Temp (observation_id int, name varchar(100), id int); 

OPEN cursor1; 

load_loop: loop 

FETCH cursor1 INTO observation_id, id1, name1, id2, name2, id3, name3, gid1, gname1, gid2, gname2, gid3, gname3; 

    IF id1 IS NOT NULL THEN 
     INSERT INTO usanpn2.Cached_Network_Observation_Temp values (observation_id, name1, id1); 
    END IF; 

    -- some additional logic here, essentially just the same as the above if statement 

END LOOP; 
CLOSE cursor1; 

END 

Это будучи SP, когда я на самом деле запустить его, все идет без сучка и задоринки, пока процесс бежит и бежит и бежит. Взглянув на активном отчете о запросе, я вижу это:

| 1076 | root | localhost        | mydb | Query | 3253 | update | INSERT INTO usanpn2.Cached_Network_Observation values (NAME_CONST('observation_id',2137912), NAME_ | 

Не положителен, где функция NAME_CONST исходит из того, что или что должно делать ничего. Я пробовал это несколько раз, переменная/строка observ_id в представлении меняется каждый раз, поэтому, похоже, она не привязана к записи.

TIA!

+1

Обработка RBAR (строка по мучительной строке). *ЗАЧЕМ*? Просто ** 'INSERT INTO Cached_Network_Observation_Temp SELECT observ_id, name1, id1 FROM usanpn2.vw_Network_Observation WHERE id1 NOT NULL' ** и делать с ним. Просто загрузите перелистающий стол. Нет необходимости запускать загрузку отдельных операторов SQL. (Вывод, показанный на выходе 'show processlist', является вставкой в ​​* другую * таблицу, без' _Temp' в конце. – spencer7593

+0

@ spencer7593 Это интересный подход!Я полагаю, я не думал об этом, потому что отдельные INSERTS должны запускаться на основе «нулевой» величины каждого из значений id. Но я могу сделать только одну вставку для каждого идентификатора в соответствии с вашим предложением. Я попробую и отправлю обратно. Тем не менее, мне все же было бы интересно узнать корень проблемы. – user470714

+2

У вас бесконечный цикл. – Uueerdo

ответ

1

Я не вижу обработчик NOT FOUND для вашего цикла выборки. Нет условия «выхода».

DECLARE done INT DEFAULT FALSE; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 

Сразу после fetch, проверить done флаг и выйти из цикла, когда это верно.

IF done THEN 
    LEAVE load_loop; 
END IF; 

Без этого, я думаю, у вас есть классический бесконечный цикл.


В заявлении показано на SHOW FULL PROCESSLIST выходе вставки в другой таблице. (Там нет _Temp в конце имя_таблицы.)


Но почему на земле вам нужен цикл курсора для обработки строки за мучительной-строкой?

Если вам нужна таблица, загрузите ее, просто загрузите перевернутый стол и сделайте это.

Заменить все, что «объявить курсор», «открытый курсор», принеси цикл, обработчик выхода, отдельные вставки заявление нонсенс с одним утверждением, что делает то, что вам нужно сделать:

INSERT INTO Cached_Network_Observation_Temp (observation_id, `name`, id) 
SELECT s.observation_id, s.name1 AS `name`, s.id1 AS id 
    FROM usanpn2.vw_Network_Observation s 
WHERE s.id1 IS NOT NULL 

Это будет быть более эффективным. И он не будет забивать двоичные журналы с разворотом ненужных инструкций INSERT. (Это также заставляет меня делать резервную копию на более крупную картинку и понимать, почему эта таблица даже нужна. Это также заставляет меня задаться вопросом, является ли представление vw_Network_Observation и необходимо ли накладные расходы на материализацию производной таблицы. Предикат в этом внешнем запрос не попадает в определение представления. MySQL обрабатывает представления много иначе, чем другие РСУБД.)

EDIT

Если следующая часть процедуры, которая закомментирована проверяет ли id2 не нуль условно вставить id2, name2 к столу _Temp, что может быть сделано таким же образом.

Или, несколько запросов могут быть объединены с оператором UNION ALL.

INSERT INTO Cached_Network_Observation_Temp (observation_id, `name`, id) 

SELECT s1.observation_id, s1.name1 AS `name`, s1.id1 AS id 
    FROM usanpn2.vw_Network_Observation s1 
WHERE s1.id1 IS NOT NULL 

UNION ALL 

SELECT s2.observation_id, s2.name2 AS `name`, s2.id2 AS id 
    FROM usanpn2.vw_Network_Observation s2 
WHERE s2.id2 IS NOT NULL 

... и т.д.

Followup

Если нужно создать несколько строк из одной строки, а число строк не неоправданно большой, я бы соблазн проверить что-то подобное, обрабатывая id1, id2, id3 и id4 одним махом, используя CROSS JOIN источника строки (s) и искусственно созданный набор из четырех рядов.

Это будет генерировать четыре строки на строку из источника строк (s), и мы можем использовать условные выражения для возврата id1, id2 и т.д.

В качестве примера, что-то вроде этого:

SELECT s.observation_id 
    , CASE n.i 
     WHEN 1 THEN s.id1 
     WHEN 2 THEN s.id2 
     WHEN 3 THEN s.id3 
     WHEN 4 THEN s.id4 
     END AS `id` 
    , CASE n.i 
     WHEN 1 THEN s.name1 
     WHEN 2 THEN s.name2 
     WHEN 3 THEN s.name3 
     WHEN 4 THEN s.name4 
     END AS `name` 
    FROM usanpn2.vw_Network_Observation s 
CROSS 
    JOIN (SELECT 1 AS i UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) n 
HAVING `id` IS NOT NULL 

Мы используем предикат в предложении HAVING вместо предложения WHERE, потому что значение, генерируемое для столбца id в наборе результатов, недоступно, когда к ним обращаются. Предикаты в предложении HAVING применяются почти последним в плане выполнения, после, к которым обращаются строки, непосредственно перед возвратом строк. (Я думаю, что «FileSort» операция, чтобы удовлетворить ORDER BY, и пункт LIMIT применяется после HAVING.)

Если количество строк, подлежащая обработке «очень большое», то мы можем получить лучшие строки обработки производительности в нескольких партиях разумного размера. Если мы делаем размер партии по два, обрабатывая две строки на INSERT, то эффективно половинки количество INSERT, которые нам нужно запустить. С 4 рядами за партию мы обрезаем это в половине. Как только мы достигнем пары десятков строк на каждую партию, у нас значительно сократил количество отдельных инструкций INSERT, которые нам нужно запустить.

Поскольку партии становятся все более крупными, наши показатели производительности становятся намного меньше. Пока партии не становятся громоздкими («слишком большими»), и мы начинаем бить на диск. Там есть «сладкое пятно» производительности между двумя крайностями (обработка одной строки за раз по сравнению с обработкой ВСЕ строк в одной партии).

+0

Справка: [https://dev.mysql.com/doc/refman/5.5/en/cursors.html](https://dev.mysql.com/doc/refman/5.5/en/cursors.html) – spencer7593

+0

Удивительный ответ @ spencer7593! Бесконечный цикл настолько очевиден, что вы это говорите. Что касается остальной части, вы правы, и я переоценил весь свой подход. Единственное, что я сделал по-другому, - это переместить запрос вида в SP, создав временную таблицу, а затем выбрать ее, чтобы сделать мои вставки. В противном случае он выбирал из/генерируя представление 6 раз, слишком медленно. Все еще нуждается в некоторой настройке, но, возможно, пришло время посмотреть на конфигурации сервера ... – user470714

+0

@ user470714: Обычно мы получаем лучшую производительность, обрабатывая «наборы» строк, а не обрабатывая отдельные строки. Это правда, до определенной степени. По мере того как наборы становятся больше («слишком большими»), наборы становятся громоздкими для некоторых операций (например, когда они отделяются на диск, и нам нужно выполнить операцию сортировки.) Обычно мы находим «сладкое пятно» производительности путем обработки строк в разумных размерах «партии». Но эта тема выходит за рамки заданного вами вопроса. (Если вы обработали этот набор «row by agonizing row» с помощью курсора, я бы предпочел позже увидеть другой вопрос, спрашивающий, как ускорить это.) – spencer7593

Смежные вопросы