Видимо я начал SELECT
запрос 20 дней назад, который так и не был завершен. Он продолжал работать, даже несмотря на то, что клиент отключился, и работал так долго, что один из журналов отмены увеличился до 230 ГБ. (Рассматриваемая база данных составляет 320 ГБ данных). Я принудительно прервал запрос, но журнал отмены просто не уменьшился до нормального размера, в результате чего диск был заполнен.
Для записи это размеры на диске:
root@the-db:/var/lib/mysql# du -h undo_00* erik_*
11G undo_001
244G undo_002
1.5G erik_temporary_undo_004.ibu
22G erik_undo_003.ibu
Интересно, что все журналы отмены довольно большие?
Я попытался разобраться в документации, но не могу заставить ее работать: https://dev.mysql.com/doc/refman/8.0/en/innodb-undo-tablespaces.html
Версия работает:
root@the-db:/var/lib/mysql# mysql --version
mysql Ver 8.0.18 for Linux on x86_64 (MySQL Community Server - GPL)
Если я правильно понимаю, чтобы поток очистки обрезал журнал отмены автоматически, необходимо выполнение трех условий:
Шаг 1. Журнал отмены должен быть больше, чем @@innodb_max_undo_log_size
, который:
mysql> SELECT @@innodb_max_undo_log_size;
+----------------------------+
| @@innodb_max_undo_log_size |
+----------------------------+
| 1073741824 |
+----------------------------+
Шаг 2. @@innodb_undo_log_truncate
должно быть ON
mysql> select @@innodb_undo_log_truncate;
+----------------------------+
| @@innodb_undo_log_truncate |
+----------------------------+
| 1 |
+----------------------------+
Шаг 3. Всего должно быть 2 активных журнала отмены. Automated truncation of undo tablespaces requires a minimum of two active undo tablespaces
(не уверен, что это означает 2 активных перед один выводится из вращения для усечения).
mysql> SELECT NAME, SPACE_TYPE, STATE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE SPACE_TYPE = 'Undo' ORDER BY NAME;
+-------------------------+------------+----------+
| NAME | SPACE_TYPE | STATE |
+-------------------------+------------+----------+
| erik_temporary_undo_003 | Undo | active |
| erik_temporary_undo_004 | Undo | active |
| innodb_undo_001 | Undo | active |
| innodb_undo_002 | Undo | inactive |
+-------------------------+------------+----------+
Согласно вышесказанному, у нас есть 3 активных и 4 полных журнала отмены.
Однако вроде ничего не происходит.
Также существует ручной процесс усечения журнала, который имеет другой набор предварительных требований.
Шаги 1 и 2 одинаковы для автоматического усечения.
Шаг 3 отличается тем, что Manual truncation of undo tablespaces requires a minimum of three active undo tablespaces
(все еще не уверен, означает ли это, что 3 активны, прежде чем один будет выведен из вращения). Чтобы обойти мою неуверенность, я создал 2 дополнительных табличных пространства отмены.
CREATE UNDO TABLESPACE erik_temporary_undo_003 ADD DATAFILE 'erik_undo_003.ibu';
CREATE UNDO TABLESPACE erik_temporary_undo_004 ADD DATAFILE 'erik_temporary_undo_004.ibu';
Шаг 4 - деактивировать табличное пространство, требующее усечения:
ALTER UNDO TABLESPACE innodb_undo_002 SET INACTIVE;
Если я правильно понимаю, это вызовет усечение, и после его завершения STATUS
будет empty
. Опять же, вот текущий статус:
mysql> SELECT NAME, SPACE_TYPE, STATE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE SPACE_TYPE = 'Undo' ORDER BY NAME;
+-------------------------+------------+----------+
| NAME | SPACE_TYPE | STATE |
+-------------------------+------------+----------+
| erik_temporary_undo_003 | Undo | active |
| erik_temporary_undo_004 | Undo | active |
| innodb_undo_001 | Undo | active |
| innodb_undo_002 | Undo | inactive |
+-------------------------+------------+----------+
Он был отключен около 3 дней назад и с тех пор не менялся.
Одна странность заключается в том, что, согласно следующему запросу, существует только 2 активных журнала отмены, тогда как предыдущий запрос показывает 3. Я что-то упускаю?
mysql> SHOW STATUS LIKE 'Innodb_undo_tablespaces%';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| Innodb_undo_tablespaces_total | 4 |
| Innodb_undo_tablespaces_implicit | 2 |
| Innodb_undo_tablespaces_explicit | 2 |
| Innodb_undo_tablespaces_active | 2 |
+----------------------------------+-------+
Не должен Innodb_undo_tablespaces_active
быть как минимум 3?
В документации упоминается innodb_purge_rseg_truncate_frequency
как способ заставить поток очистки запускаться чаще. По умолчанию 128
и в примере показано, как установить его на 32
. Что это на самом деле означает с точки зрения времени, очень неясно. Здесь просто упоминается «каждые 32 забега».
To increase that frequency, decrease the innodb_purge_rseg_truncate_frequency setting. For example, to have the purge thread look for undo tabespaces once every 32 timees[sic] that purge is invoked, set innodb_purge_rseg_truncate_frequency to 32.
Для удобства я установил его на 1.
mysql> show variables like "%truncate%";
+--------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------+-------+
| innodb_purge_rseg_truncate_frequency | 1 |
| innodb_undo_log_truncate | ON |
+--------------------------------------+-------+
Я совсем недавно понял, как получить метрики InnoDB:
mysql> set global innodb_monitor_enable = all;
И будет обновлять метрики, когда они станут доступны.
mysql> show variables like "%undo%";
+--------------------------+------------+
| Variable_name | Value |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory | ./ |
| innodb_undo_log_encrypt | OFF |
| innodb_undo_log_truncate | ON |
| innodb_undo_tablespaces | 2 |
+--------------------------+------------+
mysql> show variables like "%truncate%";
+--------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------+-------+
| innodb_purge_rseg_truncate_frequency | 1 |
| innodb_undo_log_truncate | ON |
+--------------------------------------+-------+
Я просто предполагаю, что усечение означает, что фактический файл на диске сжимается. Может это что-то значит?