Nie daj się zwieść komunikatowi o błędzie The table 'my_table' is full
. Ten rzadki scenariusz nie ma absolutnie nic wspólnego z przestrzenią dyskową. Ten pełny stan tabeli ma związek z wewnętrzną instalacją hydrauliczną InnoDB.
Najpierw spójrz na ten schemat architektury InnoDB
Należy pamiętać, że systemowy obszar tabel (plik ibdata) ma tylko 128 segmentów wycofania i 1023 miejsc wycofania na segment wycofania. Ogranicza to wielkość zdolności wycofywania transakcji. Innymi słowy, jeśli pojedynczy segment wycofania potrzebuje więcej niż 1023 miejsc do obsługi transakcji, transakcja spełni ten table is full
warunek.
Pomyśl o restauracji Red Lobster w New Jersey . Może mieć pojemność 200 osób. Jeśli restauracja jest pełna, kolejka ludzi może wyjść na zewnątrz i czekać. Jeśli ludzie na linii zniecierpliwią się, mogą wyjść, ponieważ restauracja jest pełna. Oczywiście rozwiązaniem nie byłoby powiększenie New Jersey (lub zwiększenie przestrzeni dyskowej). Rozwiązaniem byłoby powiększenie restauracji Red Lobster. W ten sposób możesz zwiększyć pojemność siedzeń, powiedzmy, do 240. Mimo to linia może utworzyć się na zewnątrz, jeśli ponad 240 osób zdecyduje się przyjechać do Red Lobster.
Aby dać przykład, miałem klienta z 2 TB systemowego obszaru tabel i wyłączono plik innodb_file_per_table . (346G dla ibdata1, reset dla ibdata2). Uruchomiłem to zapytanie
SELECT SUM(data_length+index+length) InnoDBDataIndexSpace
FROM information_schema.tables WHERE engine='InnoDB';
Następnie odejmowałem InnoDBDataIndexSpace od sumy rozmiarów plików dla ibdata1 i ibdata2. Mam dwie rzeczy, które mnie zszokowały
- W systemowym obszarze tabel pozostało 106 GB.
- Mam ten sam
Table is Full
warunek
Oznacza to, że 106 GB używało wewnętrznej instalacji hydraulicznej InnoDB. Klient korzystał wówczas z ext3.
Rozwiązaniem było dla mnie dodanie ibdata3. Omówiłem to w moim starym poście Jak rozwiązać „Tabela ... jest pełna” za pomocą „innodb_file_per_table”?
Omówiłem to również w innych postach
Pamiętaj, że ten warunek może się zdarzyć, nawet jeśli włączono opcję innodb_file_per_table . W jaki sposób? Cofnięcia i dzienniki cofania są źródłem niekontrolowanych skoków wzrostu dla ibdata1 .
TWOJA RZECZYWISTA PYTANIE
Ponieważ dodajesz indeks do tabeli i dostajesz Table is Full
, tabela musi być ogromna i nie może zmieścić się w jednym segmencie wycofywania. Musisz wykonać następujące czynności:
KROK 01
Pobierz dane do pliku zrzutu
mysqldump --no-create-info mydb mytable > table_data.sql
KROK 02
Zaloguj się do MySQL i uruchom to
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
KROK 03
Załaduj tabelę z dodatkowym indeksem z danymi
mysql -Dmydb < table_data.sql
To wszystko.
Widzisz, problem polega na tym, że ALTER TABLE spróbuje wstrzyknąć wszystkie wiersze w twojej ogromnej tabeli jako pojedynczą transakcję. Użycie mysqldump spowoduje wstawienie danych do tabeli (teraz z nowym indeksem) tysiące wierszy na raz, nie wszystkie wiersze w pojedynczej transakcji.
Nie martw się o what if this doesn't work?
Oryginalna tabela zostanie nazwana mytable_old
w przypadku czegokolwiek. może służyć jako kopia zapasowa. Możesz usunąć kopię zapasową, gdy wiesz, że nowy stół działa dla Ciebie.
Spróbuj !!!
AKTUALIZACJA 16.06.2014, 11:13 EDT
Jeśli martwisz się o większy zrzut danych, po prostu zgzipuj.
Możesz wykonać te same kroki, ale w następujący sposób
KROK 01
Pobierz dane do pliku zrzutu
mysqldump --no-create-info mydb mytable | gzip > table_data.sql.gz
KROK 02
Zaloguj się do MySQL i uruchom to
USE mydb
CREATE TABLE mytable_new LIKE mytable;
ALTER TABLE mytable_new ADD INDEX ... ;
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
KROK 03
Załaduj tabelę z dodatkowym indeksem z danymi
gzip -d < table_data.sql.gz | mysql -Dmydb
lub
gunzip < table_data.sql.gz | mysql -Dmydb
AKTUALIZACJA 16.06.2014, 12:55 EDT
Właśnie pomyślałem o innym aspekcie dotyczącym tej kwestii.
Ponieważ wykonujesz DDL, a nie DML, możliwe, że nie jest to wewnętrzna instalacja hydrauliczna InnoDB. Ponieważ DDL nie może przywrócić programu InnoDB , problemem musi być zewnętrzna instalacja hydrauliczna. Gdzie zatkana jest ta zewnętrzna hydraulika? Podejrzewam, że folder temp dla systemu operacyjnego. Dlaczego?
140616 13:04:33 InnoDB: Error: Write to file (merge) failed at offset 3 1940914176.
InnoDB: 1048576 bytes should have been written, only 970752 were written.
InnoDB: Operating system error number 0.
InnoDB: Check that your OS and file system support files of this size.
InnoDB: Check also that the disk is not full or a disk quota exceeded.
InnoDB: Error number 0 means 'Success'.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/operating-system-error-codes.html
140616 13:04:33 [ERROR] /usr/libexec/mysqld: The table 'my_table' is full
Widzisz disk quota exceeded
? Gdzie jest narzucany ten przydział dysku?
Uruchom to zapytanie
SHOW GLOBAL VARIABLES LIKE 'tmpdir';
Powiedziałeś, że to /var/lib/mysqltmp
Teraz uruchom to w systemie operacyjnym
df -h /var/lib/mysqltmp
Coś mi mówi, że /var/lib/mysqltmp
zabrakło miejsca W końcu masz tylko 14G za darmo. W oczach DDL (w celu utworzenia indeksu) wycofanie nastąpiło nie w pliku ibdata1, ale w tmpdir
lokalizacji. Jeśli /var/lib/mysqltmp
nigdzie nie jest zamontowany, dane tymczasowe są zapisywane na partycji głównej. Jeśli /var/lib/mysqltmp
gdzieś jest zamontowany, to to mocowanie jest wypełniane danymi wiersza. W obu przypadkach nie ma wystarczającej ilości miejsca na uzupełnienie DDL.
Masz tutaj dwie opcje
OPCJA 1
Możesz także utworzyć duży dysk (być może ze 100 + GB) i zamontować /var/lib/mysqltmp
na tym dużym dysku.
OPCJA 2
Moje trzyetapowe sugestie powinny nadal działać, nawet przy ograniczonej przestrzeni dyskowej
KOMENTARZ
Szkoda, że komunikat o błędzie mówi
InnoDB: Operating system error number 0.
InnoDB: Error number 0 means 'Success'.
Oznacza to, że system operacyjny jest w porządku. Nie istnieje również żaden powiązany numer błędu dla tej sytuacji.
Jest jeszcze jedna rzecz, którą powinieneś wiedzieć. Dokumentacja MySQL mówi, że szybkie tworzenie indeksu dla InnoDB wciąż trafia na dysk :
Podczas tworzenia indeksu pliki są zapisywane w katalogu tymczasowym ($ TMPDIR w systemie Unix,% TEMP% w systemie Windows lub wartość zmiennej konfiguracyjnej --tmpdir). Każdy plik tymczasowy jest wystarczająco duży, aby pomieścić jedną kolumnę tworzącą nowy indeks, a każdy z nich jest usuwany, gdy tylko zostanie scalony z indeksem końcowym.
Ze względu na ograniczenie MySQL, tabela jest kopiowana zamiast używania „Szybkiego tworzenia indeksu” podczas tworzenia indeksu na TABELI TYMCZASOWEJ. Zgłoszono to jako błąd MySQL # 39833 .
AKTUALIZACJA 16.06.2014, 13:58 EDT
[mysqld]
datadir = /mnt/cbsvolume1/var/lib/mysql
tmpdir = /mnt/cbsvolume1/var/lib/mysql
Upewnij się, że /mnt/cbsvolume1/var/lib/mysql
masz 100G lub więcej za darmo