czy jest możliwe (i jak) przekonwertować ogromną tabelę MyISAM na InnoDB bez przełączania aplikacji w tryb offline. Wymaga wstawienia kilku wierszy do tej tabeli co sekundę, ale można ją zawiesić na około 2 minuty.
Oczywiście ALTER TABLE ... silnik = innodb nie będzie działać. Dlatego planowałem utworzyć nową tabelę z silnikiem innodb i skopiować do niej zawartość. Na koniec zawieś wątek dziennika aplikacji i ZMIEŃ NAZWĘ TABELI.
Niestety nawet kopiowanie w małych partiach po 100 wierszy generuje znaczne opóźnienie po pewnym czasie.
Edycja : Istniejące wiersze nigdy się nie zmieniają, ta tabela służy do rejestrowania.
Odpowiedzi:
Utwórz konfigurację Master-Master w następujący sposób:
logTable
logTable_new
jako innodbINSERT INTO logTable_new SELECT * FROM logTable
(psuedocode) na MasterB, który wysyła replikację do MasterAlogTable_new
na MasterA zakończy synchronizację, zamień tabeleźródło
Biorąc pod uwagę ograniczenie:
Podczas rejestrowania, jeśli masz dobry sposób, aby ustawić znacznik, abyś mógł powiedzieć, od czego zaczynasz proces, abyś mógł ponownie zastosować wszystkie dzienniki lub zapisać dzienniki w pliku tekstowym, aby możesz później je spożywać
LOAD DATA INFILE
Część problemu polega na tym, że pisanie mniejszymi partiami oznacza, że indeksy muszą być przeliczane w kółko; lepiej jest uruchomić to wszystko naraz, ale może to powodować pewne „zauważalne” opóźnienie w systemie .. ale nie musisz tego robić na serwerze produkcyjnym.
LOAD DATA INFILE
)źródło
Czy dodajesz jakieś opóźnienie między każdą partią, czy po prostu dodajesz aktualizacje i uruchamiasz każdą partię bezpośrednio po poprzedniej?
Jeśli tak, spróbuj skryptować konwersję w swoim ulubionym języku za pomocą czegoś takiego:
Powinno to zapewnić, że konwersja nie zajmie więcej niż mniej więcej połowy pojemności twojego serwera, nawet uwzględniając różnice w obciążeniu nałożone, ponieważ użycie systemu zmienia się z czasem.
Lub jeśli chcesz używać tyle czasu, jak to możliwe, gdy usługa jest stosunkowo bezczynny, ale wycofać (potencjalnie zatrzymując się na dość długi czas), kiedy potrzeby baz popracować dla jego użytkowników, wymienić
sleep for as long as the update took
sięif the server's load is above <upper measure>, sleep for some seconds then check again, loop around the sleep/check until the load drops below <lower measure>
. Będzie to oznaczać, że może spokojnie płynąć naprzód, ale całkowicie zatrzyma się, gdy serwer jest zajęty wykonywaniem normalnego obciążenia. Określenie obciążenia będzie zależeć od systemu operacyjnego - w Linuksie i podobnej wartości 1-minutowa średnia wartość obciążenia/proc/loadavg
lub wynikuptime
powinien zrobić.<lower measure>
i<upper measure>
może mieć tę samą wartość, chociaż zwykle w takich kontrolkach występuje różnica, więc proces nie rozpoczyna się od razu, a następnie natychmiast zatrzymuje się z powodu własnego restartu mającego wpływ na miarę obciążenia.Oczywiście nie działałoby to w przypadku tabel, w których stare wiersze mogą zostać zmodyfikowane, ale działałyby dobrze w przypadku tabeli dziennika takiej jak ta, którą opisujesz.
W tym przypadku będziesz chciał zignorować zwykłą mądrość tworzenia indeksów po zapełnieniu nowej tabeli. Chociaż jest to rzeczywiście bardziej wydajne, jeśli chcesz, aby rzeczy były tak szybkie, jak to możliwe (wpływ na resztę systemu niech będzie przeklęty), w tym przypadku nie chcesz dużego nadmiaru obciążenia na końcu procesu, ponieważ indeksy są całkowicie tworzone za jednym razem, ponieważ jest to proces, którego nie można wstrzymać, gdy wszystko jest zajęte.
źródło
Czy coś takiego mogłoby działać?
$auto_increment
tabelamytable
zmian się nie zmieniła).$auto_increment
wartość za pomocąSHOW TABLE STATUS LIKE 'mytable'
.CREATE TABLE mytable_new LIKE mytable
ALTER TABLE mytable_new AUTO_INCREMENT=$auto_increment ENGINE=Innodb
RENAME TABLE mytable TO mytable_old, mytable_new TO mytable
INSERT INTO mytable SELECT * FROM mytable_old
.Możesz wykonać krok 7 w partiach lub w jednej instrukcji, ponieważ nie powinno to blokować normalnego logowania.
źródło