it-swarm.asia

Cara tercepat untuk memeriksa apakah tabel InnoDB telah berubah

Aplikasi saya sangat intensif basis data. Saat ini, saya menjalankan MySQL 5.5.19 dan menggunakan MyISAM, tetapi saya sedang dalam proses migrasi ke InnoDB. Satu-satunya masalah yang tersisa adalah kinerja checksum.

Aplikasi saya sekitar 500-1000 CHECKSUM TABLE pernyataan per detik pada waktu-waktu puncak, karena GUI klien melakukan polling pada database secara konstan untuk perubahan (ini adalah sistem pemantauan, jadi harus sangat responsif dan cepat).

Dengan MyISAM, ada checksum langsung yang dihitung sebelumnya pada modifikasi tabel dan SANGAT cepat. Namun, tidak ada yang seperti itu di InnoDB. Jadi, CHECKSUM TABLE SANGAT lambat.

Saya berharap dapat memeriksa waktu pembaruan terakhir dari tabel, Sayangnya, ini tidak tersedia di InnoDB juga. Saya buntu sekarang, karena tes telah menunjukkan bahwa kinerja aplikasi turun drastis.

Ada terlalu banyak baris kode yang memperbarui tabel, jadi menerapkan logika dalam aplikasi untuk mencatat perubahan tabel adalah hal yang mustahil.

Apakah ada metode cepat untuk mendeteksi perubahan dalam tabel InnoDB?

22
Jacket

Saya pikir saya sudah menemukan solusinya. Untuk beberapa waktu saya melihat Percona Server untuk mengganti server MySQL saya, dan sekarang saya pikir ada alasan bagus untuk ini.

Server Percona memperkenalkan banyak tabel INFORMATION_SCHEMA baru seperti INNODB_TABLE_STATS, yang tidak tersedia di server MySQL standar. Saat kamu melakukan:

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

Anda mendapatkan jumlah baris aktual dan penghitung. The Dokumentasi resmi mengatakan hal berikut tentang bidang ini:

Jika nilai kolom yang dimodifikasi melebihi "rows/16" atau 2000000000, perhitungan ulang statistik dilakukan ketika innodb_stats_auto_update == 1. Kita dapat memperkirakan usia statistik dengan nilai ini.

Jadi penghitung ini membungkus sesekali, tetapi Anda dapat membuat checksum dari jumlah baris dan penghitung, dan kemudian dengan setiap modifikasi tabel Anda mendapatkan checksum yang unik. Misalnya.:

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

Saya akan melakukan upgrade server saya ke server Percona jadi ini tidak masalah bagi saya. Mengelola ratusan pemicu dan menambahkan bidang ke tabel adalah masalah besar untuk aplikasi ini, karena sangat terlambat dalam pengembangan.

Ini adalah fungsi PHP yang telah saya buat untuk memastikan bahwa tabel dapat dicek dengan mesin apa pun dan server yang digunakan:

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

Anda bisa menggunakannya seperti ini:

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

Saya harap ini menghemat masalah bagi orang lain yang memiliki masalah yang sama.

3
Jacket

Untuk tabel mydb.mytable, jalankan kueri ini:

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

Jika Anda ingin tahu tabel apa yang telah berubah dalam 5 menit terakhir, jalankan ini:

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

Cobalah !!!

UPDATE 2011-12-21 20:04 EDT

Majikan saya (perusahaan hosting DB/Wweb) memiliki klien dengan 112.000 tabel InnoDB. Sangat sulit untuk membaca INFORMATION_SCHEMA.TABLES selama jam sibuk. Saya punya saran alternatif:

Jika Anda mengaktifkan innodb_file_per_table dan semua tabel InnoDB disimpan dalam .ibd file, ada cara untuk memastikan waktu pembaruan terakhir (hingga menit).

Untuk tabel mydb.mytable, lakukan hal berikut di sistem operasi:

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

Stempel waktu ini berasal dari OS. Anda tidak bisa salah dalam hal ini.

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

Tambahkan ini ke my.cnf, mulai ulang mysql, dan semua tabel InnoDB akan mengalami flush cepat dari kumpulan buffer.

Untuk menghindari memulai kembali, jalankan saja

mysql> SET GLOBAL innodb_max_dirty_pages_pct=0;

UPDATE 2013-06-27 07:15 EDT

Ketika datang untuk mengambil tanggal dan waktu untuk suatu file, ls memiliki --time-style pilihan:

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

Anda dapat membandingkan timestamp file dengan UNIX_TIMESTAMP (SEKARANG ()) .

15
RolandoMySQLDBA

Anda harus memperbarui ke Mysql v5.6 + pada versi itu innodb juga memiliki dukungan untuk tabel checksum. http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

selain itu, solusi ideal adalah jika klien Anda tidak melakukan polling untuk hasil yang konstan, tetapi Anda yang mendorong data baru dan yang diubah kapan dan jika itu tersedia. Itu akan lebih cepat dan lebih sedikit memuat di server. jika Anda menggunakan gui berbasis web, Anda harus melihat ke APE http://ape-project.org/ atau proyek serupa lainnya.

1
Gamesh

Jika Anda sebagian besar menambahkan ke tabel, Anda bisa mengaitkan AUTO_INCREMENT sebagai ukuran pembaruan.

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

Tapi saya lebih suka merujuk ke sumber otside seperti penghitung di Memcached yang akan Anda tambahkan setiap kali Anda mengubah sesuatu di database.

1
sanmai

Jawaban ini tidak ada hubungannya dengan versi atau tipe database mysql, saya ingin tahu apakah pernyataan pembaruan membuat perubahan DAN melakukan ini dalam kode php saya ..

  1. Membuat tabel dummy dengan satu catatan dan satu bidang yang ingin saya kueri untuk mendapatkan nilai current_timestamp mysql.

  2. Ke tabel data yang sedang diperbarui, tambahkan bidang cap waktu dan gunakan opsi mysql "ON UPDATE CURRENT_TIMESTAMP"

  3. Dibandingkan # 1 dan # 2

Ini tidak akan berfungsi 100% dari waktu tetapi untuk aplikasi saya itu adalah solusi yang sederhana dan bagus. Semoga ini bisa membantu seseorang

0
Steve Padgett

Anda dapat mencoba melakukan hal berikut:

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

Ini mengembalikan angka yang meningkat dengan setiap pembaruan tabel, melacaknya akan memungkinkan untuk mendeteksi perubahan.

Catatan penting: nilainya diubah segera setelah UPDATE, bukan setelah COMMIT. Jadi, Anda mungkin tidak melihat perubahan jika modifikasi dilakukan di dalam transaksi lain yang tidak selesai.

0
Romuald Brunet