Dlaczego baza danych DROP zajmuje tak dużo czasu? (MySQL)

46

Nowa instalacja CentOS.

Uruchomiłem import dużej bazy danych (plik 2 GB sql) i miałem problem. Klient SSH wydawał się tracić połączenie, a import wydawał się zawieszać. Użyłem innego okna, aby zalogować się do mysql, a import wyglądał na martwy, utknął w konkretnej tabeli wierszy 3M.

Więc próbowałem

DROP DATABASE huge_db;

15-20 minut później nic. W innym oknie zrobiłem:

/etc/init.d/mysqld restart

Komunikat w oknie DROP DB: SERVER SHUTDOWN. Następnie zrestartowałem serwer fizyczny.

Zalogowałem się ponownie do mysql, sprawdziłem, a db wciąż tam jest, uruchomiłem

DROP DATABASE huge_db;

znowu i znowu czekam już około 5 minut.

Po raz kolejny jest to świeża instalacja. Jest huge_dbto jedyna db (inna niż systemowa dbs). Przysięgam, że upuściłem db tak duże wcześniej i szybko, ale może się mylę.

Pomyślnie upuściłem bazę danych. Zajęło to około 30 minut. Zauważ też, że myślę, że się pomyliłem, kiedy myślałem, że import mysqldump nie działa. Połączenie z terminalem zostało utracone, ale myślę, że proces nadal działał. Najprawdopodobniej zabiłem importowaną tabelę środkową (tabelę wierszy 3M) i prawdopodobnie 3/4 drogi przez całą bazę danych. Mylące było to, że „top” pokazywał mysql wykorzystujący tylko 3% pamięci, kiedy wydawało się, że powinien zużywać więcej.

Upuszczenie DB skończyło się 30 minutami, więc znowu mogłem nie musieć restartować serwera i prawdopodobnie mogłem tylko poczekać na zakończenie DROP, ale nie wiem, jak mysql zareagowałby na otrzymanie zapytania DROP dla ten sam db, który importuje przez mysqldump.

Pozostaje jednak pytanie, dlaczego DROP zajmuje ponad 30 minut, aby usunąć DROP z bazy danych o pojemności 2 GB, kiedy wszystko, co trzeba zrobić, to usunąć wszystkie pliki db i usunąć wszystkie odwołania do bazy danych z schematu_informacyjnego? O co tyle szumu?

Buttle Butkus
źródło

Odpowiedzi:

73

Zamiast zabijać proces, bezpieczniej byłoby, gdybyś zrobił to w MySQL:

$ mysqladmin processlist -u root -p
Enter password: 
+-----+------+-----------+-------------------+---------+------+-------+------------------+
| Id  | User | Host      | db                | Command | Time | State | Info             |
+-----+------+-----------+-------------------+---------+------+-------+------------------+
| 174 | root | localhost | example           | Sleep   | 297  |       |                  |
| 407 | root | localhost |                   | Query   | 0    |       | show processlist |
+-----+------+-----------+-------------------+---------+------+-------+------------------+

Kwerenda o identyfikatorze 174 blokuje usunięcie „przykładowej” bazy danych, więc zanim zabijesz jakiś proces, pozwól MySQL spróbować zakończyć kwerendę:

$ mysqladmin kill 174

Uruchom processlistkomendę nad ponownie, aby potwierdzić, że został zabity.

Jeśli to nie zadziała, być może możesz pomyśleć o zabiciu błędnego procesu, ale wcześniej możesz spróbować zrestartować serwer MySQL.

Możesz także uruchamiać polecenia takie jak „SHOW FULL PROCESSLIST” i „KILL 174” w powłoce MySQL, na przykład, jeśli masz tylko klienta MySQL. Chodzi przede wszystkim o to, by unikać zabijania procesu za pomocą „zabicia” w powłoce, chyba że jest to absolutnie konieczne.

Ogólnie rzecz biorąc można użyć jednej mysqllub mysqladmin. Jednak nie powinieneś często uruchamiać takich poleceń; kiedy zaczniesz regularnie zabijać zapytania, coś jest zdecydowanie nie tak i lepiej jest rozwiązać ten problem (zabicie procesu zapytania to tylko leczenie objawu).

Stefan Magnuson
źródło
1
@BugsBuggy Powszechnym sposobem, w jaki może się to zdarzyć, jest uruchomienie innego procesu (np. Serwera WWW lub w tym przypadku procesu importowania) i połączenie go z bazą danych. Po wydaniu DROP DATABASEpolecenia serwer nie będzie kontynuował, dopóki wszystkie połączenia nie zostaną zamknięte.
Stefan Magnuson
11

Chociaż myślałem, że proces importowania wygasł, prawdopodobnie nadal trwa.

DROP DATABASEKomenda prawdopodobnie czekał na bazie aby zakończyć importowanie zanim uciekł.

Tak więc, zamiast DROP DATABASEzajmować dużo czasu, prawdopodobnie był to tylko import.

Jeśli ktoś to czyta i próbuje anulować import bazy danych i upuścić bazę danych, zalecamy najpierw znaleźć PID (identyfikator procesu) dla importu i uruchomić go z innego terminalu:

$ kill [PID]

... gdzie [PID] byłoby rzeczywistym PID dla procesu.

Powinieneś natychmiast zobaczyć zatrzymanie importu, jeśli drugi terminal jest nadal podłączony.

Możesz także uruchomić SHOW PROCESSLISTna karcie SQL phpMyAdmin. Wynikowa tabela pokazuje uruchomione procesy i kliknięcie „x” obok wiersza, który chcesz zabić, powinno załatwić sprawę.

Następnie uruchomić

DROP DATABASE `database_name`;

I wszystko powinno być czyste.


Inna odpowiedź sugeruje, że zabicie procesu w mysql jest lepsze niż robienie tego z zewnątrz. Nie przetestowałem tej odpowiedzi, ale brzmi to bardzo realistycznie. Dlatego zaznaczyłem to jako „zaakceptowaną odpowiedź” zamiast tej.

Buttle Butkus
źródło
3

Spróbuj obciąć największe tabele w bazie danych youra, zanim ją upuścisz. Widziałem bardzo podobne zachowanie podczas pracy z archiwami MySQL ruchu zapory i to bardzo pomogło.

Tim Brigham
źródło
Według dokumentów MySQL: „Obcinaj operacje upuszczania i ponownego tworzenia tabeli, co jest znacznie szybsze niż usuwanie wierszy jeden po drugim”, więc nie ma sensu skracać operacji usuwania
ejoubaud
3

Napotkałem ten sam problem. Ale tym razem sprawdziłem pokaż listę procesów; powiedział, że sprawdzanie uprawnień przez dłuższy czas. Potem odkryłem, że mysqld_safe działa jako root, podczas gdy uprawnienia na poziomie folderu były tylko dla użytkownika mysql. Stąd zabiłem kwerendę, oczywiście zajęło dużo czasu mówiąc, że jest w stanie zabitym, ale czekałem, aż zareaguje, następnie zabiło kwerendę i zmieniłem uprawnienia na poziomie folderu do rootowania również poprzez dodanie go do grupy i chmod do 770. Następnie wykonałem ta sama baza danych upuść bla; to zadziałało dla mnie w 2 sekundy dla bazy danych 20 GB.

Mannoj
źródło