Найшвидший спосіб перевірити, чи змінилася таблиця InnoDB


22

Моя програма дуже інтенсивна. Наразі я запускаю MySQL 5.5.19 і використовую MyISAM, але я переходжу до InnoDB. Єдина проблема, що залишилася - це продуктивність контрольної суми.

У моїй програмі CHECKSUM TABLEв пік є близько 500-1000 заяв в секунду, оскільки GUI клієнтів постійно обстежує базу даних для змін (це система моніторингу, тому повинна бути дуже чуйною і швидкою).

У MyISAM є реальні контрольні суми, які попередньо розраховуються на модифікацію таблиці та ДУЖЕ швидко. Однак у InnoDB такого немає. Отже, CHECKSUM TABLEДУЖЕ повільно.

Я сподівався, що зможу перевірити останній час оновлення таблиці, на жаль, це також недоступне в InnoDB. Зараз я застряг, бо тести показали, що продуктивність програми різко падає.

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

Чи існує швидкий метод виявлення змін у таблицях InnoDB?

Відповіді:


15

Для таблиці mydb.mytable запустіть цей запит:

SELECT update_time
FROM information_schema.tables
WHERE table_schema='mydb'
AND table_name='mytable';

Якщо ви хочете знати, які таблиці змінилися за останні 5 хвилин, запустіть це:

SELECT table_schema,table_name,update_time
FROM information_schema.tables
WHERE update_time > (NOW() - INTERVAL 5 MINUTE);

Спробувати !!!

ОНОВЛЕННЯ 2011-12-21 20:04 EDT

У мого роботодавця (DB / Wweb hosting comany) є клієнт із 112 000 таблиць InnoDB. Дуже важко читати INFORMATION_SCHEMA.TABLES у години пік. У мене є альтернативна пропозиція:

Якщо у вас включено innodb_file_per_table і всі таблиці InnoDB зберігаються у .ibdфайлах, є спосіб встановити час останнього оновлення (до хвилини).

Для таблиці mydb.mytable виконайте такі дії в операційній системі:

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

Ця мітка часу від ОС. Ви не можете помилитися на цьому.

ОНОВЛЕННЯ 2011-12-21 22:04 EDT [mysqld] innodb_max_dirty_pages_pct = 0;

Додайте це до my.cnf, перезапустіть mysql, і всі таблиці InnoDB випробовують швидкі спалахи з пулу буфера.

Щоб уникнути перезавантаження, просто запустіть

mysql> SET GLOBAL innodb_max_dirty_pages_pct=0;

ОНОВЛЕННЯ 2013-06-27 07:15 EDT

Щодо пошуку дати та часу для файлу, ls має --time-styleможливість:

$ cd /var/lib/mysql/mydb
$ ls -l --time-style="+%s" mytable.ibd | awk '{print $6}'

Ви можете порівняти часову позначку файлу з UNIX_TIMESTAMP (NOW ()) .


Ви впевнені, що не можете помилитися з моддацією idb? Зміна може бути просто життям в буферному пулі в пам'яті, а ще не змилося на диску.
atxdba

6
Дякую за відповідь, але, як я вже сказав, update_time в information_schema.tables становить NULL для таблиць InnoDB. Крім того, я не впевнений, що innodb_max_dirty_pages_pct = 0 - це гарна ідея, тому що це принесе жертву продуктивності ... Я думав про рішення з тригерами, щоб вставити випадкове значення у довідкову таблицю для кожної з переглянутих таблиць, але потім Мені знадобляться 3 тригери на стіл лише для цього ...
Куртка

Також вибір з information_schema.tables теж повільний ... мені потрібно близько 300 мс, щоб перевірити одну таблицю. Для порівняння, для того, щоб зробити "CHECKSUM TABLE" на таблиці MyISAM з мільйонами рядків з увімкненою функцією Live Checksum потрібно менше мілісекунди.
Куртка

2
+1 для перевірки файлової системи, якщо промивка буфера є достатньо регулярною (приблизно один раз в секунду - це за замовчуванням), тоді ця марка часу буде досить точною і, ймовірно, достатньо хорошою для більшості випадків ...
Дейв Рікс

1
Можливо, це добре для локальної бази даних, але у мене є кілька віддалених рабів, тому це не працює ...
Jacket

3

Я думаю, що я знайшов рішення. Деякий час я дивився на Percona Server, щоб замінити свої сервери MySQL, і тепер я думаю, що для цього є вагомі причини.

Сервер Percona представляє багато нових таблиць INFORMATION_SCHEMA, таких як INNODB_TABLE_STATS, який недоступний на стандартному сервері MySQL. Коли ви робите:

SELECT rows, modified FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table'

Ви отримуєте фактичну кількість рядків та лічильник. Офіційна документація говорить наступне про це поле:

Якщо значення модифікованого стовпця перевищує "рядки / 16" або 2000000000, перерахунок статистики проводиться, коли innodb_stats_auto_update == 1. Ми можемо оцінити старість статистики за цим значенням.

Тож цей лічильник обертається раз у раз, але ви можете робити контрольну суму кількості рядків та лічильника, а потім із кожною модифікацією таблиці ви отримуєте унікальну контрольну суму. Наприклад:

SELECT MD5(CONCAT(rows,'_',modified)) AS checksum FROM information_schema.innodb_table_stats WHERE table_schema='db' AND table_name='table';

Я все-таки збирався модернізувати свої сервери до сервера Percona, так що це обмеження не є проблемою для мене. Управління сотнями тригерів та додаванням полів до таблиць є головним болем для цього додатка, оскільки це дуже пізно в розробці.

Це функція PHP, яку я придумав, щоб переконатися, що таблиці можна перевіряти, незалежно від використання двигуна та сервера:

function checksum_table($input_tables){
    if(!$input_tables) return false; // Sanity check
    $tables = (is_array($input_tables)) ? $input_tables : array($input_tables); // Make $tables always an array
    $where = "";
    $checksum = "";
    $found_tables = array();
    $tables_indexed = array();
    foreach($tables as $table_name){
        $tables_indexed[$table_name] = true; // Indexed array for faster searching
        if(strstr($table_name,".")){ // If we are passing db.table_name
            $table_name_split = explode(".",$table_name);
            $where .= "(table_schema='".$table_name_split[0]."' AND table_name='".$table_name_split[1]."') OR ";
        }else{
            $where .= "(table_schema=DATABASE() AND table_name='".$table_name."') OR ";
        }
    }
    if($where != ""){ // Sanity check
        $where = substr($where,0,-4); // Remove the last "OR"
        $get_chksum = mysql_query("SELECT table_schema, table_name, rows, modified FROM information_schema.innodb_table_stats WHERE ".$where);
        while($row = mysql_fetch_assoc($get_chksum)){
            if($tables_indexed[$row[table_name]]){ // Not entirely foolproof, but saves some queries like "SELECT DATABASE()" to find out the current database
                $found_tables[$row[table_name]] = true;
            }elseif($tables_indexed[$row[table_schema].".".$row[table_name]]){
                $found_tables[$row[table_schema].".".$row[table_name]] = true;
            }
            $checksum .= "_".$row[rows]."_".$row[modified]."_";
        }
    }

    foreach($tables as $table_name){
        if(!$found_tables[$table_name]){ // Table is not found in information_schema.innodb_table_stats (Probably not InnoDB table or not using Percona Server)
            $get_chksum = mysql_query("CHECKSUM TABLE ".$table_name); // Checksuming the old-fashioned way
            $chksum = mysql_fetch_assoc($get_chksum);
            $checksum .= "_".$chksum[Checksum]."_";
        }
    }

    $checksum = sprintf("%s",crc32($checksum)); // Using crc32 because it's faster than md5(). Must be returned as string to prevent PHPs signed integer problems.

    return $checksum;
}

Ви можете використовувати його так:

// checksum a signle table in the current db
$checksum = checksum_table("test_table");

// checksum a signle table in db other than the current
$checksum = checksum_table("other_db.test_table");

// checksum multiple tables at once. It's faster when using Percona server, because all tables are checksummed via one select.
$checksum = checksum_table(array("test_table, "other_db.test_table")); 

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


Подальша розробка історії для тих, хто цікавиться: forum.percona.com/…
Куртка

1

Ви повинні оновити до Mysql v5.6 + у цій версії innodb також підтримує таблицю контрольної суми. http://dev.mysql.com/doc/refman/5.6/uk/checksum-table.html

Крім цього, ідеальним рішенням було б, якби ваш клієнт не опитувався на результат постійно, а замість вас, де висували нові та змінені дані, коли і якщо вони були доступні. Це було б швидше і менше навантаження було б на сервері. якщо ви користуєтеся веб-інтерфейсом gui, ви повинні заглянути в APE http://ape-project.org/ або інші подібні проекти.


На жаль, це вбивця продуктивності. Контрольна сума складається з перемішування всіх рядків одна за одною . З Документів: "Цей рядковий за рядком обчислення - це те, що ви отримуєте з пунктом EXTENDED, з InnoDB та всіма іншими системами зберігання даних, окрім MyISAM, і з таблицями MyISAM, не створеними за допомогою пункту CHECKSUM = 1" :-(
LSerni

1

Якщо ви в основному додаєте до таблиці, ви можете підключити AUTO_INCREMENT як міру оновленості.

SELECT `AUTO_INCREMENT` FROM `information_schema`.`tables` 
WHERE `table_schema` = DATABASE() AND `table_name` = 'YOUR_TABLE';

Але я вважаю за краще посилатись на таке джерело, як лічильник у Memcached, який ви збільшуватимете щоразу, коли щось змінитимете в базі даних.


0

Ви можете спробувати зробити наступне:

SELECT rows_changed
FROM information_schema.table_statistics
WHERE table_schema = 'mydb' AND table_name='mytable';

Це повертає число, яке збільшується з кожним оновленням таблиці, відстеження цього дозволить виявити зміни.

Важлива примітка: значення змінюється відразу після оновлення, а не після COMMIT. Таким чином, ви не можете побачити зміни, якщо зміни були зроблені в іншій транзакції, яка не закінчилася.


0

Ця відповідь не має нічого спільного з версіями або типами баз даних mysql, я хотів знати, чи вносяться зміни в операторах оновлення І робити це в моєму PHP-коді.

  1. Створив макетну таблицю з одним записом і одним полем, яке я б запитав, щоб отримати значення current_timestamp mysql.

  2. До таблиці даних, що оновлюється, додано поле часової позначки та використано опцію mysql "НА ОНОВЛЕННЯ CURRENT_TIMESTAMP"

  3. Порівняно №1 та №2

Це не спрацює 100% часу, але для мого застосування це було простим і чудовим рішенням. Сподіваюсь, це комусь допомагає

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