Виконання тригера проти збереженої процедури в MySQL


11

Публікація тут на DBA.StackExchange ( які найкращі практики для запуску для підтримки ревізійного номера записів? ) Породила цікаве питання (принаймні, цікаве для мене) щодо продуктивності в MySQL.

Контекст полягає в тому, що ми хочемо вставити запис у таблицю для кожного оновленого рядка. Перед оновленням рядка ми хочемо зберегти попереднє значення, а потім збільшити один із стовпців (стовпець "версія").

Якщо ми робимо це всередині тригера, це добре виходить. Для MySQL тригери розташовуються рядом за рядком , тому це було б простим рішенням. Виберіть дані, що перебувають у таблиці, вставте їх у таблицю журналу та оновіть стовпець "версія" в нових даних.

Однак можна перемістити цю логіку до збереженої процедури. Якщо ви це зробите, ви виконуєте вставку, збільшуючи стовпець "версія" в таблиці. Вся справа була б встановлена ​​на основі.

Отож, якщо мова йде про виконання цієї вставки, чи буде це більш ефективно використовувати набір заданих методів збереженої процедури або підхід, заснований на тригері?

Це питання стосується MySQL (оскільки він має тригери "рядок за рядком"), хоча може застосовуватися до інших СУБД тригера "рядок за рядком".


1
Слід пам’ятати про те, що логіку версії слід підштовхувати до збереженої процедури - наскільки згорбленим ти будеш, коли хтось якимось чином записує в таблицю, минаючи ваш механізм аудиту?
billinkc

Я згоден. Але на іншому кінці шкали, можливо, ви хочете навмисно обійти цю реєстрацію за певних обставин. Звичайно, це зовсім інше питання . Мені просто цікаво наслідки для виступу.
Річард

Відповіді:


7

Для простоти тригери - це шлях для впровадження будь-якого виду відстеження змін бази даних. Однак вам потрібно знати, що відбувається під кришкою, коли ви використовуєте тригери.

Відповідно до програмування збережених процедур MySQL , на сторінці 256 під заголовком "Тригер перекриття" зазначено наступне:

Важливо пам’ятати, що, за необхідності, тригери додають накладні витрати до оператора DML, до якого вони застосовуються. фактична кількість накладних витрат буде залежати від характеру тригера, але --- оскільки всі тригери MySQL виконуються ДЛЯ КОЖОГО РОЗУМУ - накладні витрати можуть швидко накопичуватися для операторів, які обробляють велику кількість рядків. Тому слід уникати розміщення будь-яких дорогих операторів SQL або процедурного коду в тригерах.

На сторінках 529-531 наводиться розширене пояснення накладних наділів. Заключний пункт із цього розділу визначає наступне:

Урок ось такий: оскільки код тригера буде виконуватися один раз для кожної рядки, на яку впливає оператор DML, тригер може легко стати найважливішим фактором продуктивності DML. Код всередині корпусу тригера повинен бути максимально легким і, зокрема, - будь-які оператори SQL в тригері повинні підтримуватися індексами, коли це можливо.

Не згаданий у книзі є ще одним фактором при використанні тригерів: Що стосується журналу аудиту, будь ласка, пам’ятайте про те, в які дані ви входите. Я говорю це тому, що якщо ви вирішите увійти до таблиці MyISAM, кожен INSERT в таблицю MyISAM виробляє повне блокування таблиці під час INSERT. Це може стати серйозним вузьким місцем в умовах великого трафіку та транзакцій з високим рівнем транзакцій. Крім того, якщо тригер проти таблиці InnoDB і ви реєструєте зміни в MyISAM зсередини тригера, це таємно відключатиме відповідність ACID (тобто зменшує блокові транзакції до поведінки автокомісії), яку неможливо відмовити назад.

При використанні тригерів на таблицях InnoDB та реєстрації змін

  • Таблиця, в яку ви входите, також є InnoDB
  • У вас вимкнено автокомісію
  • Ви налаштовуєте НАЧАЛЬНУ ПЕРЕКЛАДУ ... COMMIT / ROLLBACK ретельно блокує

Таким чином журнали аудиту можуть скористатися COMMIT / ROLLBACK, як і основні таблиці.

Що стосується використання збережених процедур, вам доведеться ретельно викликати збережену процедуру в кожній точці DML проти таблиці, яка відстежується. Можна легко пропустити зміни в реєстрації в особі десятків тисяч рядків коду програми. Якщо розмістити такий код в тригері, виключає пошук усіх цих операторів DML.

КАВАТИ

Залежно від того, наскільки складний спусковий гачок, він все ще може бути вузьким місцем. Якщо ви хочете зменшити вузькі місця при реєстрації аудиту, ви можете щось зробити. Однак знадобиться невелика зміна інфраструктури.

Використовуючи товарне обладнання, створіть ще два сервери БД

Це дозволить серверу зменшити введення / виведення запису в основну базу даних (MD) завдяки журналу аудиту. Ось як це можна зробити:

Крок 01) Увімкніть двійковий журнал в основній базі даних.

Крок 02) Використовуючи недорогий сервер, встановіть MySQL (та ж версія, що і MD) з увімкненою бінарною реєстрацією. Це буде DM. Реплікація налаштування від MD до DM.

Крок 03) Використовуючи другий недорогий сервер, встановіть MySQL (та ж версія, що і MD), коли бінарний журнал вимкнено. Налаштуйте кожну таблицю аудиту для використання --replicate-do-table . Це буде АС. Реплікація налаштування від DM до AU.

Крок 04) mysqldump структури таблиці з MD та завантажте її в DM та AU.

Крок 05) Перетворіть усі таблиці аудиту в MD для використання двигуна зберігання BLACKHOLE

Крок 06) Перетворіть усі таблиці в DM та AU для використання двигуна зберігання BLACKHOLE

Крок 07) Перетворіть усі таблиці аудиту в АС для використання механізму зберігання даних MyISAM

Коли закінчено

  • DM копіюватиме з MD та записуватиме речі лише у свій бінарний журнал
  • За допомогою - повторювати фільтр таблиць до всіх таблиць аудиту, AU буде реплікувати з DM

Для цього потрібно зберігати інформацію про аудит на окремому сервері БД, а також зменшувати будь-яку деградацію вводу / виводу запису, яку матиме MD.


Чудова відповідь +++ 1
b_dubb

1

Ось підхід для масового виконання цього оновлення.

Для цього прикладу

  • table_A має PRIMARY KEY id
  • Ви створюєте таблицю під назвою table_A_Keys2Update з ідентифікатором як PRIMARY KEY
  • Ви заповнюєте таблицю_A_Keys2Update за допомогою ідентифікаторів ідентифікаторів з таблиці_A, які знаєте, що потрібно оновити

Для створення table_A_Keys2Update зробіть наступне:

CREATE TABLE table_A_Keys2Update SELECT id FROM table_A;
ALTER TABLE table_A_Keys2Update ADD PRIMARY KEY (id);

Після того, як ви заповните table_A_Keys2Update за допомогою ідентифікаторів, чий номер редакції потрібно наростити, виконайте наступне ОНОВЛЕННЯ ПРИЄДНУЙТЕСЯ, щоб збільшити номер ревізії всіх рядків, ідентифікатор яких і в table_A, і в table_A_Keys2Update:

UPDATE table_A A INNER JOIN table_A_Keys2Update B USING (id)
SET A.revision = A.revision + 1;

Цей запит на один рядок може замінити тригер і збережену процедуру.

За бажанням, ви можете розмістити цей запит у збереженій процедурі та викликати його, якщо цього хочете.


Це справді Вставка, про яку мені цікаво. Якщо ви ВСТАВЛИЛИ в аудит SELECT <що б не було> ВІД <первинний_таблиця> ДЕ <параметри зі збереженої процедури>, ви можете зробити вставку оптом. У триггері ви просто ВСТАВИТИ В АВТОРІЙНІ ЦЕНТРИ <дані з оновленого рядка> . Отже, чи буде вставка одного рядка за рядком швидшою, ніж об'ємна вставка?
Річард

Для простоти, тригер буде набагато кращим 1) за умови, що основний_табель ніколи не відчуває масових вставок посеред будь-якого пікового періоду; 2) інформацію про аудит потрібно читати на вимогу в будь-який момент і 3) ваш сайт є малолюдним.
RolandoMySQLDBA
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.