MySQL, aby przyspieszyć wgrywanie danych udostępnia przydatną funkcję – wyłącza indeksy. Dzięki temu, podczas wgrywania danych do tabeli nie ma potrzeby przebudowywania struktury indeksu po każdym INSERTcie. Po wgraniu danych włączamy obsługę indeksów i są one odbudowywane raz, w momencie gdy wszystkie dane są już na miejscu w tabeli.

Wszystko jest dobrze, jeśli po zakończeniu operacji indeksy zostaną włączone. Tu już niestety trzeba uważać, szczególnie gdy wgrywamy dump przygotowany przy pomocy mysqldump. Struktura takiego zrzutu wygląda z grubsza w ten sposób:

DROP TABLE IF EXISTS `tabela`;
CREATE TABLE `tabela` (...);
LOCK TABLES `tabela` WRITE;
/*!40000 ALTER TABLE `tabela` DISABLE KEYS */;
INSERT INTO `tabela` VALUES (...);
/*!40000 ALTER TABLE `tabela` ENABLE KEYS */;
UNLOCK TABLES;

Jak widać, włączenie obsługi indeksów odbywa się po wgraniu danych – to oczywiście jest jedyne sensowne rozwiązanie. Tyle tylko, że jeśli przerwiemy wgrywanie danych do tabeli, to do włączenia indeksów już nie dojdzie. Tabela pozostanie bez działających indeksów. Jak to się musi skończyć, szczególnie gdy tabela ta jest często wykorzystywana w zapytaniach, nie muszę chyba mówić. Jak można sprawdzić, czy obsługa indeksów jest włączona? Wyłączmy je najpierw.

mysql> ALTER TABLE articles DISABLE KEYS;
Query OK, 0 rows affected (0,04 sec)

mysql> SHOW INDEXES FROM articles;
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+----------+
|  Table    | Non_unique | Key_name     | Seq_in_index | Column_name  |  Collation | Cardinality | Sub_part | Packed | Null | Index_type |  Comment  |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+----------+
|  articles |          0 | PRIMARY      |            1 | id           |  A         |          14 |     NULL | NULL   |      | BTREE       |          |
| articles |          1 | show_on_home |            1 |  show_on_home | A         |           2 |     NULL | NULL   | YES  |  BTREE      | disabled |
| articles |          1 | idx_category  |            1 | category     | A         |          14 |     NULL |  NULL   |      | BTREE      | disabled |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+----------+
3 rows in set (0,00 sec)

Jak widać, w kolumnie `Comment` dla indeksów innych niż klucz główny (jego nie da się wyłączyć – zawsze będzie działać) pojawia się wartość ‚disabled’. Oznacza to, że dany indeks nie funkcjonuje. Włączmy je:

mysql> ALTER TABLE articles ENABLE KEYS;
Query OK, 0 rows affected (0,04 sec)

mysql> SHOW INDEXES FROM articles;
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
|  Table    | Non_unique | Key_name     | Seq_in_index | Column_name  |  Collation | Cardinality | Sub_part | Packed | Null | Index_type |  Comment |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
|  articles |          0 | PRIMARY      |            1 | id           |  A         |          14 |     NULL | NULL   |      | BTREE       |         |
| articles |          1 | show_on_home |            1 |  show_on_home | A         |           2 |     NULL | NULL   | YES  |  BTREE      |         |
| articles |          1 | idx_category  |            1 | category     | A         |          14 |     NULL |  NULL   |      | BTREE      |         |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
3 rows in set (0,00 sec)

Jak widać, ‚disabled’ znikło, indeksy działają.

Ostatnio miałem okazję mieć styczność z taką sytuacją – duża część tabel miała wyłączone indeksy. W efekcie trzeba było na szybko uruchomić je dla każdej z tabel na serwerze. Do tego przydatny okazał się skrypt mk-find z pakietu Maatkit. Skrypt ten służy do wyciągania listy tabel, które spełniają zadane warunki. Może to być wielkość, może to być czas utworzenia lub ostatniej modyfikacji. Można także przy jego pomocy generować raporty o stanie tabel – ilość danych, ilość danych w indeksie itp. W moim przypadku wykorzystałem możliwość generowania przez mk-find zapytań, które są przesyłane do serwera MySQL:

mk-find --printf "%D.%N\n" --exec "alter table %D.%N enable keys;";

Polecenie to wyświetla na ekranie listę baz danych i tabel, a dodatkowo dla aktualnej bazy i tabeli wykonuje polecenie ‚ALTER TABLE `baza`.`tabela` ENABLE KEYS;’.
Polecam zapoznać się z tym skryptem – przydatna sprawa jeśli potrzebujemy zautomatyzować pewne prace administracyjne.