Jaki jest najbardziej efektywny sposób grupowania zapytań UPDATE w MySQL?

10

Piszę aplikację, która musi wypłukiwać dużą liczbę aktualizacji bazy danych przez dłuższy okres czasu, i utknąłem przy tym, jak zoptymalizować zapytanie. Obecnie używam INSERT INTO ... VALUES (..), (..) ON DUPLICATE KEY UPDATE, który działa, aby spakować wszystkie wartości do jednego zapytania, ale wykonuje się niesamowicie wolno na dużych tabelach. W rzeczywistości nigdy nie muszę wstawiać wierszy.

Inne podejścia, które widziałem, to aktualizacja przy użyciu SET value = CASE WHEN...(co byłoby trudne do wygenerowania ze względu na sposób, w jaki buduję zapytania i nie jestem pewien co do wydajności CASEsetek / tysięcy kluczy), i po prostu wielokrotne połączenie aktualizacje. Czy którekolwiek z nich byłoby szybsze niż moja obecna metoda?

Zaskakuje mnie, że o ile wiem, nie ma idiomatycznego, skutecznego sposobu na zrobienie tego w MySQL. Jeśli naprawdę nie ma sposobu, który ON DUPLICATE KEYbyłby szybszy niż , czy warto byłoby przełączyć się na PostgreSQL i użyć jego UPDATE FROMskładni?

Wszelkie inne sugestie są również mile widziane!

Edycja: oto jedna z tabel, która jest często aktualizowana. Usunąłem nazwy kolumn, ponieważ są one nieistotne.

CREATE TABLE IF NOT EXISTS `table` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `a` bigint(20) unsigned NOT NULL DEFAULT '0',
  `b` bigint(20) unsigned NOT NULL DEFAULT '0',
  `c` enum('0','1','2') NOT NULL DEFAULT '0',
  `d` char(32) NOT NULL,
  -- trimmed --
  PRIMARY KEY (`id`),
  KEY `a` (`a`),
  KEY `b` (`b`),
  KEY `c` (`c`),
  KEY `d` (`d`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
jli
źródło
To jest na maszynie testującej, a nie na produkcji, więc InnoDB nie jest całkowicie dostrojony. Nie jestem całkowicie pewien, jak działa INSERT FROM, ale to, co powiedziałeś, wydaje się słuszne. Zaktualizowałem pytanie o informacje, o które prosiłeś.
jli

Odpowiedzi:

14

Ponieważ używasz InnoDBtabel, najbardziej oczywistą optymalizacją byłoby zgrupowanie wielu UPDATEs w transakcję.

Będąc InnoDBsilnikiem transakcyjnym, płacisz nie tylko za UPDATEsiebie, ale także za cały narzut transakcyjny: zarządzanie buforem transakcji, dziennik transakcji, opróżnianie dziennika na dysk.

Jeśli logicznie nie podoba ci się ten pomysł, spróbuj pogrupować 100-1000 UPDATEs naraz, za każdym razem zapakowane w ten sposób:

START TRANSACTION;
UPDATE ...
UPDATE ...
UPDATE ...
UPDATE ...
COMMIT;

Możliwe wady:

  • Jeden błąd zwinie całą transakcję (ale można go łatwo naprawić w kodzie)
  • Możesz długo czekać, aby zgromadzić swoje 1000 UPDATEs, więc możesz też chcieć trochę czasu
  • Większa złożoność kodu aplikacji.
Shlomi Noach
źródło