it-swarm-eu.dev

Nejrychlejší způsob, jak zkontrolovat, zda se tabulka InnoDB změnila

Moje aplikace je velmi náročná na databázi. V současné době provozuji MySQL 5.5.19 a používám MyISAM, ale právě přecházím na InnoDB. Jediným problémem, který zbývá, je výkon kontrolního součtu.

Moje aplikace má asi 500–1 000 CHECKSUM TABLE příkazy za sekundu ve špičkách, protože GUI klientů neustále dotazuje databázi na změny (jedná se o monitorovací systém, takže musí být velmi pohotový a rychlý).

U systému MyISAM jsou k dispozici živé kontrolní součty, které jsou přepočteny podle úpravy tabulky a jsou velmi rychlé. V InnoDB však nic takového neexistuje. Tak, CHECKSUM TABLE je VELMI pomalý.

Doufal jsem, že si budu moci zkontrolovat poslední čas aktualizace tabulky. Bohužel to také není k dispozici v InnoDB. Jsem uvízl nyní, protože testy ukázaly, že výkon aplikace drasticky klesá.

Existuje prostě příliš mnoho řádků kódu, které aktualizují tabulky, takže implementace logiky v aplikaci na změny tabulky protokolu není vyloučena.

Existuje nějaká rychlá metoda k detekci změn v tabulkách InnoDB?

22
Jacket

Myslím, že jsem našel řešení. Nějakou dobu jsem se díval na server Percona, abych nahradil své servery MySQL, a teď si myslím, že je k tomu dobrý důvod.

Percona server zavádí mnoho nových tabulek INFORMATION_SCHEMA jako INNODB_TABLE_STATS, které nejsou dostupné na standardním serveru MySQL. Když:

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

Získáte skutečný počet řádků a počítadlo. Oficiální dokumentace říká o tomto poli následující:

Pokud hodnota upraveného sloupce překročí „řádky/16“ nebo 2000000000, provede se přepočet statistik, když innodb_stats_auto_update == 1. Můžeme odhadnout stáří statistik podle této hodnoty.

Tento čítač se tak za časem zalomí, ale můžete provést kontrolní součet počtu řádků a čítače a při každé úpravě tabulky získáte jedinečný kontrolní součet. Např.:

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

Chtěl jsem přesto upgradovat své servery na server Percona, takže toto ohraničení pro mě není problém. Správa stovek spouště a přidávání polí do tabulek je pro tuto aplikaci hlavní bolest, protože se vývoj vyvíjí velmi pozdě.

Toto je funkce PHP, kterou jsem přišel, aby bylo zajištěno, že tabulky mohou být zkontrolovány bez ohledu na použitý stroj a server):

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;
}

Můžete to použít takto:

// 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")); 

Doufám, že to ušetří potíže dalším lidem, kteří mají stejný problém.

3
Jacket

V tabulce mydb.mytable spusťte tento dotaz:

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

Pokud chcete vědět, jaké tabulky se za posledních 5 minut změnily, spusťte toto:

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

Pokusit se !!!

UPDATE 2011-12-21 20:04 EDT

Můj zaměstnavatel (hostující společnost DB/Wweb) má klienta se 112 000 tabulkami InnoDB. Je velmi obtížné číst INFORMACI_SCHEMA.TABLES během špiček. Mám alternativní návrh:

Pokud máte zapnutou innodb_file_per_table a všechny tabulky InnoDB jsou uloženy v .ibd soubory, existuje způsob, jak zjistit čas poslední aktualizace (až do minuty).

V tabulce mydb.mytable proveďte v operačním systému následující:

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

Toto časové razítko je z operačního systému. Na tomhle se nemůžete pokazit.

UPDATE 2011-12-21 22:04 EDT [mysqld] innodb_max_dirty_pages_pct = 0;

Přidejte toto do my.cnf, restartujte mysql a všechny tabulky InnoDB zažijí rychlé vyprázdnění z fondu vyrovnávacích pamětí.

Chcete-li zabránit restartování, stačí spustit

mysql> SET GLOBAL innodb_max_dirty_pages_pct=0;

UPDATE 2013-06-27 07:15 EDT

Pokud jde o načtení data a času pro soubor, ls má --time-style možnost:

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

Můžete porovnat časové razítko souboru s UNIX_TIMESTAMP (NOW ()) .

15
RolandoMySQLDBA

Měli byste aktualizovat na Mysql v5.6 + v této verzi innodb také podporuje tabulku kontrolních součtů. http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

dalším řešením by bylo ideální řešení, pokud by váš klient nepřicházel o výsledek neustále, ale místo toho, kde tlačíte nová a změněná data, kdykoli a kdy byla dostupná. Bylo by to rychlejší a menší zatížení by bylo na serveru. Pokud používáte webové gui, měli byste se podívat do APE http://ape-project.org/ nebo jiných podobných projektů.

1
Gamesh

Pokud většinou přidáváte do tabulky, můžete se připojit k AUTO_INCREMENT jako měřítku aktualizovatelnosti.

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

Ale já bych raději odkazoval na zdroj otside jako čítač v Memcached, který budete zvyšovat pokaždé, když něco změníte v databázi.

1
sanmai

Tato odpověď nemá nic společného s verzemi nebo typy databází mysql, chtěl jsem vědět, jestli aktualizační příkazy dělají změny A dělat to v mém php kódu.

  1. Vytvořil jsem fiktivní tabulku s jedním záznamem a jedním polem, které bych dotazoval, abych získal hodnotu aktuálníhotimestampu mysql.

  2. Do aktualizované tabulky údajů bylo přidáno pole časových razítek a byla použita možnost mysql „ON UPDATE CURRENT_TIMESTAMP“

  3. Porovnáno # 1 a # 2

To nebude fungovat 100% času, ale pro mou aplikaci to bylo jednoduché a skvělé řešení. Doufám, že to někomu pomůže

0
Steve Padgett

Můžete zkusit následující:

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

Vrací číslo, které se zvyšuje s každou aktualizací tabulky, její sledování umožní detekovat změnu.

Důležitá poznámka: hodnota je změněna okamžitě po UPDATE, ne po COMMIT. Změny tedy nemusíte vidět, pokud byly změny provedeny v rámci jiné transakce, která nebyla dokončena.

0
Romuald Brunet