Usuwanie i odzyskiwanie miejsca z tabeli InnoDB

14

Mam tabelę InnoDB o pojemności 700 GB, do której nie zapisuję już żadnych danych (tylko czytam). Chciałbym usunąć starsze przechowywane w nim dane i odzyskać to miejsce na dysku (gdy mi się kończy). Usunięcie części jest dość łatwe, ponieważ mam indeks główny auto-inc, dzięki czemu mogę po prostu iterować fragmenty, używając go i usuwać wiersze, ale to nie przywróci mi miejsca. Zakładam, że OPTIMIZE TABLEtak, ale może to potrwać wiecznie na stole o pojemności 700 GB, więc czy jest inna opcja, którą przeoczam?

Edytuj przez RolandoMySQLDBA

Zakładając, że twoja tabela jest mydb.mytable, uruchom następującą kwerendę i opublikuj ją tutaj, aby określić miejsce na dysku potrzebne do zmniejszenia tabeli:

SELECT
    FORMAT(dat/POWER(1024,3),2) datsize,
    FORMAT(ndx/POWER(1024,3),2) ndxsize,
    FORMAT((dat+ndx)/POWER(1024,3),2) tblsize
FROM (SELECT data_length dat,index_length ndx
FROM information_schema.tables WHERE
table_schema='mydb' AND table_name='mytable') A;

Musimy także zobaczyć strukturę tabeli, jeśli jest to dozwolone.

Edytuj przez Noam

To jest wynik zapytania:

datsize ndxsize tblsize
682,51 47,57 730.08

To jest struktura tabeli ( SHOW CREATE TABLE)

`CREATE TABLE `mybigtable` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL,  
  `created_at` datetime NOT NULL,  
  `tid` bigint(20) NOT NULL,  
  `text` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, 
  `ft` tinyint(1) NOT NULL,  
  `irtsd` bigint(20) NOT NULL,  
  `irtuid` int(11) NOT NULL,  
  `rc` int(11) NOT NULL,  
  `r` tinyint(1) NOT NULL,  
  `e` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,  `timezone` varchar(5) NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `uid_tid` (`uid`,`tid`)) ENGINE=InnoDB AUTO_INCREMENT=2006963844 DEFAULT CHARSET=utf8`
Noam
źródło
Czy masz inny wolumin dysku, aby przechwycić tylko dane?
RolandoMySQLDBA
@RolandoMySQLDBA Mam zewnętrzny dysk twardy, który mogę zamontować. To się liczy?
Noam
@RolandoMySQLDBA, ale oczywiście chcielibyśmy usunąć trochę miejsca bez konieczności posiadania kolejnych 700 GB
Noam
@RolandoMySQLDBA Czy dodatkowy rozmiar dysku powoduje problemy z wydajnością?
Aris,
@ Irys może to zależeć od dysku i jego czasu wyszukiwania. W dzisiejszych czasach większość dysków działa teraz lepiej, ale po co marnować cykle (nawet bardzo szybko), jeśli masz duże rzadkie kieszenie miejsca na dysku ??? Jest to szczególnie prawdziwe w przypadku InnoDB, który normalnie jest ustawiony na 16K bloków. Przy wewnętrznej fragmentacji bloków 16K możesz defragmentować tabelę za pomocą ALTER TABLE ... ENGINE=InnoDB;(jeśli masz na to miejsce). Większość jest zadowolona ze swoich bardzo szybkich dysków SSD i nie będzie się już martwić.
RolandoMySQLDBA,

Odpowiedzi:

21

To dobre pytanie. Masz kilka rozwiązań, ale twój stół jest dość duży, więc żadne nie będzie bez bólu :)

Masz trzy rozwiązania do „zmniejszania” tabel InnoDB:

1. OPTYMALIZUJ TABELĘ

Możesz używać OPTIMIZE TABLEtak jak wspomniałeś, ale powinieneś dbać o innodb_file_per_tablezmienną:

mysql> show variables like "innodb_file_per_table";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)

Pozwól mi wyjaśnić:

Za pomocą OPTIMIZE TABLEtabel InnoDB blokuje się tabelę, kopiuje dane do nowej czystej tabeli (dlatego wynik jest pomniejszony), upuszcza oryginalną tabelę i zmienia nazwę nowej tabeli z oryginalną nazwą. Dlatego powinieneś zadbać o to, aby podwoić wolumetrię swojego stołu dostępną na dysku (podczas pracy potrzebujesz 2x700 GB).

Gdy jesteś w innodb_file_per_table = ON. Wszystkie tabele mają odpowiedni plik danych. Więc…OPTIMIZE instrukcja utworzy nowy plik danych (~ 700 GB) po zakończeniu operacji, MySQL usunie oryginalny plik i zmieni nazwę nowego (więc na koniec 700 GB - prawdopodobnie mniej, ponieważ zostanie zmniejszone - danych) wygenerowane podczas operacji zostaną zwolnione)

Gdy jesteś w pliku innodb_file_per_table = OFF. Wszystkie dane trafiają do jednego pliku danych: ibdata . Ten plik ma smutną cechę, nie można go zmniejszyć. Tak więc w trakcie OPTIMIZEprocesu tworzona jest nowa tabela (blisko 700 GB), ale nawet po operacji upuszczania i zmiany nazwy (i na końcu OPTIMIZEfazy) twoja ibdata nie zwolni ~ ~ 700 GB, więc chciałeś zwolnić trochę danych, ale masz 700 GB więcej, spoko, prawda?

2. ZMIEŃ TABELĘ

Możesz także użyć ALTER TABLEinstrukcji, ALTER TABLEbędzie działać w taki sam sposób jak OPTIMIZE TABLE. Możesz po prostu użyć:

ALTER TABLE myTable EGINE=InnoDB;

3. ALTER TABLE (ONLINE)

Problem OPTIMIZEi ALTER TABLEże blokuje tabeli podczas pracy. Możesz użyć narzędzia Percona: pt-online-schema-change (z Percona Toolkit: link ). pt-online-schema ... zbuduje mechanizm z wyzwalaczami i tabelą tymczasową, które pozwolą, aby oryginalna tabela była dostępna do odczytu i zapisu podczas operacji. Używam tego narzędzia w produkcji, ALTERponieważ jest całkiem fajne.

Pamiętaj, że powinieneś FOREIGN KEYodwoływać się do tabeli, FK i powoduje ryzyko wywołania bałaganu. Aby sprawdzić te wymagania wstępne, zapytaj:

mysql> SELECT COUNT(*) FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE REFERENCED_TABLE_NAME = "myTable";
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+
1 row in set (0.04 sec)

Oto jak używam zmiany pt-online-schemat:

pt-online-schema-change --alter "ENGINE=InnoDB" D=myBase,t=myTable --user --ask-pass

Zauważ, że moja uwaga na temat innodb_file_per_table jest prawdziwa także dla tego rozwiązania.

4. mysqldump

Ostatnim rozwiązaniem jest odtworzenie wszystkich baz danych ze zrzutu. Strasznie długie, ale strasznie wydajne. Pamiętaj, że jest to jedyne rozwiązanie, aby „zmniejszyć” plik ibdata.

Max.

Maxime Fouilleul
źródło
Również w opcji Percona online w tabeli zmian potrzebuję 700 GB wolnego miejsca na dysku?
Noam
Tak, pt-online po prostu użyj trochę mechaniki, aby zrobić ALTER online, ale i tak zmienia się.
Maxime Fouilleul
@MaximeFouilleul czy dodatkowy rozmiar dysku powoduje jakiekolwiek problemy z wydajnością?
Aris,
1

Jeśli masz mało miejsca na dysku, sugeruję, abyś zrobił to tak, jak Max sugerował przy zmianie pt-online-schemat-zmiana (ONLINE). Byłem w tej samej sytuacji ze znacznie mniejszym stołem (200 GB) i zdecydowałem się na kompresję w tym samym czasie. Coś w tym stylu powinno działać:

pt-online-schema-change --alter="ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4" D=myBase,t=myTable --user --ask-pass

Działa to tylko wtedy, gdy masz format pliku barracuda i format tabeli COMPACT. Musisz także mieć włączoną opcję innodb_file_per_table. Może to robić cuda na podstawie wielkości tabeli, szczególnie jeśli jest dużo tekstu i jeśli używasz mniejszego KEY_BLOCK_SIZE, takiego jak 8K lub nawet 4K (domyślnie 16K). Możesz także sprawdzić, ile miejsca możesz zyskać na wielu testach porównawczych dotyczących tego problemu na innych blogach, ale dokumentacja MySQL reklamuje od 25% do 50% (dla mnie było to prawie 90%).

Zauważ, że może to również wpłynąć na wydajność podczas wykonywania SELECT (z dokumentacji MySQL):

Zatem w dowolnym momencie pula buforów może zawierać zarówno skompresowane, jak i nieskompresowane formy strony, lub tylko skompresowaną formę strony, lub żadną.

MySQL musi również rozpakować dane, gdy nie znajduje się w puli buforów. Więc bądźcie ostrzeżeni.

To naprawdę działało dobrze w moim przypadku. Miałem długi tekst. 200 GB stało się 26 GB. Występy nie uległy zmianie.

Aby uzyskać więcej szczegółowych informacji, sprawdź te linki:

https://dev.mysql.com/doc/refman/5.5/en/innodb-compression-usage.html

https://dev.mysql.com/doc/refman/5.5/en/innodb-compression-internals.html

Emeric Hunter
źródło