Як знайти та виправити фрагментовані таблиці MySQL


27

Я використав MySQLTuner, який вказав, що деякі таблиці були фрагментовані. я використав

mysqlcheck --оптимізувати -A

для оптимізації всіх таблиць. Він зафіксував деякі таблиці, але MySQLTuner все ще знаходить 19 фрагментів. як я можу побачити, які таблиці потребують дефрагментації? Можливо, ОПТИМІЗУВАТИ ТАБЛИЦУ буде працювати там, де mysqlcheck цього не зробив? Або що ще слід спробувати?


1
У мене схожа проблема. Я налаштовую нову БД з MySQL 5.5 та певними таблицями InnoDB, які ніколи не розшифровуються. Мені цікаво, чи перевірка Data_free (показана у відповіді KayakJim) невірна з таблицями InnoDB.
docwhat

Відповіді:


38

коротка відповідь:

select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

Відповідь "Ви мусите знати"

спочатку ви повинні зрозуміти, що таблиці Mysql стають фрагментарними, коли рядок оновлюється, тож це нормальна ситуація. Коли створена таблиця, скажімо, імпортовано за допомогою дампа з даними, всі рядки зберігаються без фрагментації на багатьох сторінках фіксованого розміру. Коли ви оновлюєте рядок змінної довжини, сторінка, що містить цей рядок, ділиться на дві або більше сторінок, щоб зберігати зміни, і ці нові дві (або більше) сторінки містять порожні пробіли, заповнюючи невикористаний простір.

Це не впливає на продуктивність, якщо, звичайно, фрагментація не зростає занадто сильно. Що таке занадто велика фрагментація, давайте подивимось запит, який ви шукаєте:

  select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

DATA_LENGTH та INDEX_LENGTH - це простір, який використовуються вашими даними та індексами, а DATA_FREE - загальна кількість байтів, невикористаних на всіх сторінках таблиці (фрагментація).

Ось приклад реальної виробничої таблиці

| ENGINE | TABLE_NAME               | data_length | index_length | data_free |
| InnoDB | comments                 |         896 |          316 |         5 |

У цьому випадку ми маємо Таблицю, використовуючи (896 + 316) = 1212 МБ, і маємо дані вільного простору 5 Мб. Це означає "співвідношення фрагментації":

5/1212 = 0.0041

... Що є дійсно низьким «коефіцієнтом фрагментації».

Я працював із таблицями із співвідношенням близько 0,2 (мається на увазі 20% порожніх пробілів) і ніколи не помічаю уповільнення запитів, навіть якщо оптимізую таблицю, продуктивність однакова. Але застосування таблиці оптимізації на столі 800 Мб займає багато часу і блокує таблицю протягом декількох хвилин, що неможливо в виробництві.

Отже, якщо врахувати, що ви виграєте у продуктивності та витрачений час на оптимізацію таблиці, я вважаю за краще НЕ ОПТИМІЗУВАТИ.

Якщо ви вважаєте, що це краще для зберігання, перегляньте ваше співвідношення та подивіться, скільки місця ви можете заощадити під час оптимізації. Зазвичай це не надто багато, тому я вважаю за краще НЕ ОПТИМІЗУВАТИ.

А якщо оптимізувати, наступне оновлення створить порожні пробіли, розділивши сторінку на дві або більше. Але швидше оновити фрагментовану таблицю, ніж не фрагментовану, тому що, якщо таблиця фрагментована, оновлення на рядок необов'язково розбиває сторінку.

Я сподіваюся, що це вам допоможе.


1
Хоча це відповідь кілька років тому, я подумав, що зазначу, що data_free є статистикою для всього простору таблиць, а не для відповідної таблиці. Якщо ви зберігаєте кілька таблиць разом в одному просторі таблиць, data_free може ввести вас в оману, вважаючи, що таблиця потребує дефрагментації, коли це просто означає, що в просторі таблиць є вільні розширення. Запуск таблиці оптимізації не зменшить безкоштовні розширення. Дефрагментація таблиці може навіть збільшити вільні розширення .
Білл Карвін

14

Просто для додання відповіді від Felipe-Rojas ви можете обчислити коефіцієнт фрагмента як частину запиту:

select ENGINE,
  concat(TABLE_SCHEMA, '.', TABLE_NAME) as table_name,
  round(DATA_LENGTH/1024/1024, 2) as data_length,
  round(INDEX_LENGTH/1024/1024, 2) as index_length,
  round(DATA_FREE/1024/1024, 2) as data_free,
  (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
ORDER BY frag_ratio DESC;

Якщо таблиця розбита на невеликий відсоток (менше 5%?), Ви, ймовірно, можете залишити її в спокої.

Все, що більше, і вам потрібно буде оцінити, виходячи з використання db, блокуючих таблиць тощо, наскільки важливо дефрагментацію таблиці.


2

Таблиця оптимізації дійсно вирішить проблему.

Якщо у вас є лише кілька баз даних, ви можете скористатися PHPMyAdmin, щоб пройти всі ваші бази даних. Виберіть таблиці з накладними витратами, а потім виберіть для оптимізації.

Якщо у вас багато баз даних, можливо, кращим буде інший метод.

Я використовую наступні налаштування скриптів PHP в cron, щоб працювати щогодини.

$DB = new mysqli ('localhost', 'DbUser', 'DbPassword');
$results = $DB->query('show databases');
$allDbs = array();
while ($row = $results->fetch_array(MYSQLI_NUM))
{
    $allDbs[] = $row[0];
}
$results->close();
foreach ($allDbs as $dbName)
{
    if ($dbName != 'information_schema' && $dbName != 'mysql')
    {
        $DB->select_db($dbName);
        $results = $DB->query('SHOW TABLE STATUS WHERE Data_free > 0');
        if ($results->num_rows > 0)
        {
            while ($row = $results->fetch_assoc())
            {
                $DB->query('optimize table ' . $row['Name']);
            }
        }
        $results->close();
    }
}
$DB->close();

3
Я впевнений, що mysqlcheck --optimize -Aце те саме, що і SQLOPTIMIZE TABLE <tablename>;
док.

2

Я натрапив на цю сторінку і виявив, що запити Felipe-Rojas та sysadmiral є дуже корисними. Але в моєму випадку я запустив запит у phpMyAdmin WHM, і отримати лише TABLE_NAME було не так корисно, оскільки база даних не була перерахована, і кілька баз даних мають однакові назви таблиць. Отже, просто додавання TABLE_SCHEMAнадасть і цей стовпець.

select  ENGINE, TABLE_SCHEMA, TABLE_NAME, Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free, (data_free/(index_length+data_length)) as frag_ratio from information_schema.tables  where  DATA_FREE > 0 order by frag_ratio desc

Показує БД

ENGINE  | TABLE_SCHEMA  | TABLE_NAME    | data_length   | index_length  | data_free | frag_ratio

InnoDB  | db_name       | db_table      | 0             | 0             | 8         | 170.6667

Для "виправлення" я використав посилання таблиці дефрагментацій у phpMyAdmin для кожної з таблиць, що призвело до високого "frag_ratio", для якого phpMyAdmin виконує:

ALTER TABLE `table_name` ENGINE = InnoDB;

0

Таблиця, яка використовує InnoDB Engine MySQL, по суті, ніколи не повинна бути OPTIMIZEd.

Значення Data_freeвід information_schema.tablesабо SHOW TABLE STATUSдуже часто не дорівнює нулю, навіть якщо ви думаєте, що зробили все, що можете зробити, дефрагментуйте свої таблиці. Крім того, ця метрика є лише однією з декількох фрагментів, які можуть і трапляються. (Також марно витрачений простір у блоках, скасування списків, індекс BTrees проти даних BTrees тощо тощо)

І innodb_file_per_tableускладнює використання Data_free. Якщо таблиця знаходиться в ibdata1, тоді Data_freeпосилається на весь простір таблиць; досить марне число. Якщо таблиця є у власному .ibdфайлі, ймовірно, це буде декілька МБ або кілька відсотків від розміру таблиці, залежно від того, що більша.

Тільки якщо ви видалили багато рядків і не збираєтесь поповнювати таблицю, можливо, варто запустити OPTIMIZE TABLE.

PARTITIONsтакож показують тривожну кількість Data_free, оскільки кожен розділ зазвичай показує 4-7 МБ "безкоштовно". І це не піде.

Чому дефрагментація?

  • Щоб повернути простір в ОС? Ну, ви могли б цього досягти коротко, якби innodb_file_per_table=1. Але додаючи рядки, ви повернете їх назад з ОС.
  • Щоб пришвидшити доступ? Забудь це. Розташування блоків на диску є відносно випадковим і є останні кілька десятиліть. Півстоліття тому було дещо важливо переставити блоки.
  • Збалансувати BTrees? Так? Вони негайно знову стануть неврівноваженими. Стаціонарний стан для BTrees, які випадковим чином вставляються, становить 69%. І це навіть не враховується Data_free.
  • MySQLTuner каже? Цей продукт потрібно охолодити.

Записка історії. Коли я допомагав DBA в основному таблиць MyISAM, я виявив, мабуть, 2 з 1000 таблиць, які допомагали щомісяця OPTIMIZE . З тих пір я працював з тисячами таблиць InnoDB, але ще не знайшов проблеми з продуктивністю, якій, ймовірно, допоможуть OPTIMIZE. (Звичайно, виникли проблеми з дисковим простором, які OPTIMIZEможуть допомогти, але це стає складніше - зазвичай у DBA не вистачає місця на диску OPTIMIZE!)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.