Jak usunąć fragmentację z tabel InnoDB?

13

Mam bazę danych o liczbie tabel.

Chcę usunąć niektóre rekordy z tabel, które mówią, że liczba rekordów jest większa niż 20 000 lub 50 000.

Wszystkie tabele są InnoDB. I file_per_tablejest wyłączony .

Kiedy usunę rekordy z wielu tabel, nastąpi ich fragmentacja.

Czy istnieje sposób na usunięcie fragmentacji.

Aktualizacja 17 kwietnia

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

Więc teraz moje pytanie brzmi: w jaki sposób zdecyduję, że moje tabele są pofragmentowane, czy nie.

Abdul Manaf
źródło
Dokumenty
1
I artykuł InnoDB: dbaj o fragmentację ze strony bloga Percona.
ypercubeᵀᴹ

Odpowiedzi:

14

Rozwiązałem to w StackOverflow w październiku 2010 roku .

Pamiętaj o najbardziej zajętym pliku w infrastrukturze InnoDB: / var / lib / mysql / ibdata1

Ten plik zwykle zawiera cztery rodzaje informacji

  • Dane tabeli
  • Indeksy tabel
  • Dane MVCC (Multiversioning Concurrency Control)
  • Metadane tabeli (lista identyfikatorów obszaru tabel)

Uruchamianie OPTIMIZE TABLEz tabelą InnoDB przechowywaną w ibdata1 ma dwie rzeczy:

  • Sprawia, że ​​dane tabeli i indeksy są ciągłe w ibdata1, dzięki czemu dostęp jest szybszy
  • Sprawia, że ​​ibdata1 rośnie, ponieważ ciągłe dane i strony indeksowe są dołączane do ibdata1

Podczas gdy możesz segregować dane tabel i indeksy tabel od ibdata1 i zarządzać nimi niezależnie za pomocą innodb_file_per_table , duża rozbieżność całego miejsca na dysku w ibdata1 po prostu nie zniknie i nie będzie można go odzyskać. Musisz zrobić więcej.

Aby raz na zawsze zmniejszyć ibdata1 , wykonaj następujące czynności:

1) MySQL Zrzuć wszystkie bazy danych do pliku tekstowego SQL (nazwij go /root/SQLData.sql)

2) Usuń wszystkie bazy danych (oprócz schematu mysql)

3) Zamknij mysql

4) Dodaj następujące wiersze do /etc/my.cnf

[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G

Uwaga: Niezależnie od tego, jaki zestaw masz dla innodb_buffer_pool_size, upewnij się, że innodb_log_file_size to 25% innodb_buffer_pool_size.

5) Usuń ibdata1, ib_logfile0 i ib_logfile1

W tym momencie powinien istnieć tylko schemat mysql w katalogu / var / lib / mysql

6) Uruchom ponownie mysql

Spowoduje to ponowne utworzenie ibdata1 przy 10 lub 18 MB (w zależności od wersji MySQL), ib_logfile0 i ib_logfile1 przy 1G każdy

7) Ponownie załaduj /root/SQLData.sql do mysql

ibdata1 wzrośnie, ale będzie zawierał tylko metadane tabeli. W rzeczywistości będzie rosła bardzo powoli z biegiem lat. Jedynym sposobem szybkiego wzrostu ibdata1 jest posiadanie jednego lub więcej z poniższych:

  • Wiele DDL ( CREATE TABLE, DROP TABLE, ALTER TABLE)
  • Dużo transakcji
  • Wiele zmian do zatwierdzenia na transakcję

Każda tabela InnoDB będzie istniała poza ibdata1

Załóżmy, że masz tabelę InnoDB o nazwie mydb.mytable. Jeśli przejdziesz do / var / lib / mysql / mydb, zobaczysz dwa pliki reprezentujące tabelę

  • mytable.frm (nagłówek silnika pamięci masowej)
  • mytable.ibd (Home of Table Data and Table Indexs for mydb.mytable)

ibdata1 nigdy nie będzie już zawierał danych i indeksów InnoDB.

Dzięki opcji innodb_file_per_table w /etc/my.cnf można uruchomić, OPTIMIZE TABLE mydb.mytable;a plik /var/lib/mysql/mydb/mytable.ibd faktycznie się zmniejszy.

Robiłem to wiele razy w mojej karierze jako MySQL DBA

W rzeczywistości, kiedy pierwszy raz to zrobiłem, zwinąłem 50 GB pliku ibdata1 do 500 MB.

Spróbuj. Jeśli masz dodatkowe pytania, napisz do mnie. Zaufaj mi. Będzie to działać w krótkim okresie i na dłuższą metę !!!

AKTUALIZACJA 2012-04-19 09:23 EDT

Po uruchomieniu powyższych kroków, w jaki sposób można ustalić, które tabele należy poddać defragmentacji? Można się dowiedzieć, ale będziesz miał skrypt.

Oto przykład: Załóżmy, że masz tabelę mydb.mytable. Po włączeniu innodb_file_per_table masz plik /var/lib/mysql/mydb/mytable.ibd

Będziesz musiał pobrać dwie liczby

FILESIZE FROM OS: Możesz sprawdzić rozmiar pliku w systemie operacyjnym w ten sposób

ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'

FILESIZE FROM INFORMATION_SCHEMA: Możesz sprawdzić rozmiar pliku z Information_schema.tables w następujący sposób:

SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';

Wystarczy odjąć wartość INFORMACJE_SCHEMA od wartości OS i podzielić różnicę przez wartość INFORMACJA_SCHEMA.

Następnie zdecydujesz, jaki procent uważa za konieczne defragmentację tej tabeli. Oczywiście defragmentujesz go za pomocą jednego z następujących poleceń:

OPTIMIZE TABLE mydb.mytable;

lub

ALTER TABLE mydb.mytable ENGINE=InnoDB;
RolandoMySQLDBA
źródło
nie sądzę, że / var / lib / mysql / ibdata1 jest bardzo zajęty, jeśli używasz zalecanej opcji innodb_file_per_table = 1
CrackerJack9
1
@ CrackerJack9 ibdata1 jest niesamowicie przepełniony z powodu tego, co się w nim dzieje: 1) Informacje o podwójnym buforze zapisu, 2) Wstaw bufor dla indeksów wtórnych, 3) Słownik danych, 4) Wycofywanie segmentów, 5) Cofnij przestrzeń tabel. Proszę goto scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing dla obrazowego przedstawienia tych rzeczy. Nawet po usunięciu danych i stron indeksu dla tabel InnoDB, ibdata1 nadal może znacznie wzrosnąć w środowisku o wysokiej transakcji.
RolandoMySQLDBA
1
@ CrackerJack9 Mam dodatkowy post omawiający dodatkowe działania związane z ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA
Nie zdawałem sobie sprawy, że wciąż był tak intensywnie wykorzystywany. Mile widziane!
CrackerJack9
@RolandoMySQLDBA Czy potrafisz pop w stosie, kiedy masz czas?
ypercubeᵀᴹ
5

Jeśli często usuwasz wiersze (lub aktualizujesz wiersze o typach danych o zmiennej długości), możesz skończyć z dużą ilością zmarnowanego miejsca w plikach danych, podobnie jak fragmentacja systemu plików.

Jeśli nie korzystasz z tej innodb_file_per_tableopcji, jedyne, co możesz z tym zrobić, to wyeksportować i zaimportować bazę danych, co jest procedurą wymagającą dużo czasu i miejsca na dysku.

Ale jeśli używasz innodb_file_per_table, możesz zidentyfikować i odzyskać to miejsce!

Przed 5.1.21 licznik wolnego miejsca jest dostępny w kolumnie table_comment w pliku information_schema.tables. Oto kilka instrukcji SQL służących do identyfikacji tabel z co najmniej 100 mln (faktycznie 97,65 mln) wolnego miejsca:

WYBIERZ schemat_tabeli, nazwa_tabeli, table_comment OD
informacji_schema.tables GDZIE SILNIK LUBI „InnoDB” ORAZ table_comment RLIKE „InnoDB wolny: ([0-9] {6,}). * ';

Począwszy od 5.1.21 przeniesiono to do kolumny data_free (o wiele bardziej odpowiednie miejsce):

WYBIERZ schemat_tabeli, nazwa_tabeli, wolny_danych / 1024/1024 AS wolny_danych_MB Z MBA_tablicowych_informacji.TABELE GDZIE PODOBNY SILNIK „InnoDB” ORAZ wolny od danych> 100 * 1024 * 1024;

Możesz odzyskać utracone miejsce, odbudowując stół. Najlepszym sposobem na to jest użycie „alter table” bez faktycznej zmiany:

ALTER TABLE `TableName` ENGINE=InnoDB;

To właśnie robi MySQL za kulisami, jeśli uruchomisz „optymalizację tabeli” na tabeli InnoDB. Spowoduje to blokadę odczytu, ale nie blokadę pełnego stołu. To, jak długo to zajmie, zależy całkowicie od ilości danych w tabeli (ale nie od wielkości pliku danych). Jeśli masz tabelę z dużą liczbą operacji usuwania lub aktualizacji, możesz chcieć uruchamiać to co miesiąc, a nawet co tydzień.

Mahesh Patil
źródło
Jeszcze jedna rzecz, której nie jestem w stanie zrozumieć, co oznacza data_free> 100 * 1024 * 1024 ..? A kiedy zobaczyłem wynik, nie jestem w stanie zdecydować, czy tabela jest pofragmentowana, czy nie ...? Czy jest jakiś sposób, aby można powiedzieć, że tabela jest pofragmentowana lub nie.
Abdul Manaf
spójrz na moją aktualizację.
Abdul Manaf