Cách nhanh nhất để kiểm tra xem bảng InnoDB có thay đổi không


22

Ứng dụng của tôi rất chuyên sâu về cơ sở dữ liệu. Hiện tại, tôi đang chạy MySQL 5.5.19 và sử dụng MyISAM, nhưng tôi đang trong quá trình chuyển sang InnoDB. Vấn đề duy nhất còn lại là hiệu suất tổng kiểm tra.

Ứng dụng của tôi thực hiện khoảng 500-1000 CHECKSUM TABLEcâu lệnh mỗi giây trong thời gian cao điểm, vì GUI khách hàng đang thăm dò cơ sở dữ liệu liên tục để thay đổi (đây là một hệ thống giám sát, do đó phải rất nhạy và nhanh).

Với MyISAM, có các tổng kiểm tra trực tiếp được tính toán trước khi sửa đổi bảng và RẤT nhanh. Tuy nhiên, không có điều đó trong InnoDB. Vì vậy, CHECKSUM TABLElà RẤT chậm.

Tôi đã hy vọng có thể kiểm tra thời gian cập nhật cuối cùng của bảng, Thật không may, điều này cũng không có sẵn trong InnoDB. Bây giờ tôi đang bị mắc kẹt, bởi vì các thử nghiệm đã chỉ ra rằng hiệu suất của ứng dụng giảm mạnh.

Đơn giản là có quá nhiều dòng mã cập nhật các bảng, do đó, việc triển khai logic trong ứng dụng để ghi nhật ký thay đổi là không cần thiết.

Có phương pháp nhanh nào để phát hiện các thay đổi trong bảng InnoDB không?

Câu trả lời:


15

Đối với bảng mydb.mytable, hãy chạy truy vấn này:

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

Nếu bạn muốn biết bảng nào đã thay đổi trong 5 phút qua, hãy chạy này:

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

Hãy thử một lần !!!

CẬP NHẬT 2011-12-21 20:04 EDT

Chủ lao động của tôi (DB / Wweb hosting comany) có một khách hàng với 112.000 bảng InnoDB. Rất khó để đọc THÔNG TIN_SCHema.TABLES trong giờ cao điểm. Tôi có một đề nghị thay thế:

Nếu bạn đã bật innodb_file_per_table và tất cả các bảng InnoDB được lưu trữ trong .ibdcác tệp, có một cách để xác định thời gian của bản cập nhật cuối cùng (tối đa đến phút).

Đối với bảng mydb.mytable, hãy làm như sau trong hệ điều hành:

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

Dấu thời gian này là từ hệ điều hành. Bạn không thể sai về điều này.

CẬP NHẬT 2011-12-21 22:04 EDT [mysqld] innodb_max_denty_pages_pct = 0;

Thêm phần này vào my.cnf, khởi động lại mysql và tất cả các bảng InnoDB sẽ trải nghiệm các lần xả nhanh từ nhóm bộ đệm.

Để tránh khởi động lại, chỉ cần chạy

mysql> SET GLOBAL innodb_max_dirty_pages_pct=0;

CẬP NHẬT 2013-06-27 07:15 EDT

Khi nói đến việc lấy ngày và thời gian cho một tệp, ls có --time-styletùy chọn:

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

Bạn có thể so sánh dấu thời gian của tệp với UNIX_TIMESTAMP (NOW ()) .


Bạn có chắc chắn bạn không thể đi sai với moddate idb? Một thay đổi có thể chỉ là sống trong vùng đệm trong bộ nhớ và chưa được đưa vào đĩa.
atxdba

6
Cảm ơn câu trả lời, nhưng như tôi đã nói, update_time trong information_schema.tables là NULL cho các bảng InnoDB. Ngoài ra, tôi không chắc rằng innodb_max_denty_pages_pct = 0 là một ý tưởng hay, bởi vì nó sẽ hy sinh hiệu năng ... Tôi đã suy nghĩ về một giải pháp với các kích hoạt, để chèn một giá trị ngẫu nhiên vào một bảng tham chiếu cho mỗi bảng được xem, nhưng sau đó Tôi sẽ chỉ cần 3 kích hoạt mỗi bàn cho việc này ...
Áo khoác

Ngoài ra, việc chọn từ information_schema.tables cũng khá chậm ... tôi mất khoảng 300ms để kiểm tra một bảng. Để so sánh thực hiện "BẢNG KIỂM TRA" trên bảng MyISAM với hàng triệu hàng được bật Kiểm tra trực tiếp, mất ít hơn một phần nghìn giây.
Áo khoác

2
+1 cho kiểm tra hệ thống tệp, miễn là việc xả bộ đệm đủ thường xuyên (khoảng một lần mỗi giây là mặc định), thì dấu thời gian này sẽ khá chính xác và có lẽ đủ tốt cho hầu hết các trường hợp ...
Dave Rix

1
Có thể nó ổn đối với cơ sở dữ liệu cục bộ, nhưng tôi có nhiều nô lệ từ xa, vì vậy điều này không hoạt động ...
Áo khoác

3

Tôi nghĩ rằng tôi đã tìm thấy giải pháp. Trong một thời gian, tôi đã tìm kiếm Percona Server để thay thế các máy chủ MySQL của mình và bây giờ tôi nghĩ có một lý do chính đáng cho việc này.

Máy chủ Percona giới thiệu nhiều bảng Information_SCHema mới như INNODB_TABLE_STATS, không có sẵn trong máy chủ MySQL tiêu chuẩn. Khi bạn làm:

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

Bạn nhận được số hàng thực tế và một quầy. Các tài liệu chính thức cho biết sau đây về lĩnh vực này:

Nếu giá trị của cột được sửa đổi vượt quá hàng Hàng / 16, hoặc 2000000000, việc tính toán lại số liệu thống kê được thực hiện khi innodb_stats_auto_update == 1. Chúng tôi có thể ước tính mức độ cũ của số liệu thống kê theo giá trị này.

Vì vậy, bộ đếm này thỉnh thoảng kết thúc, nhưng bạn có thể thực hiện tổng kiểm tra số lượng hàng và bộ đếm, và sau đó với mỗi lần sửa đổi bảng bạn sẽ có một tổng kiểm tra duy nhất. Ví dụ:

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

Tôi sẽ nâng cấp máy chủ của mình lên máy chủ Percona vì vậy giới hạn này không phải là vấn đề đối với tôi. Quản lý hàng trăm trình kích hoạt và thêm các trường vào bảng là một nỗi đau lớn cho ứng dụng này, vì nó rất muộn trong quá trình phát triển.

Đây là chức năng PHP mà tôi đã đưa ra để đảm bảo rằng các bảng có thể được kiểm tra lại bất cứ công cụ và máy chủ nào được sử dụng:

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

Bạn có thể sử dụng nó như thế này:

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

Tôi hy vọng điều này sẽ cứu một số rắc rối cho những người khác có cùng vấn đề.


Phát triển câu chuyện hơn nữa cho những ai quan tâm: forum.percona.com/
Áo khoác

1

Bạn nên cập nhật lên Mysql v5.6 + tại phiên bản đó innodb cũng có hỗ trợ bảng tổng kiểm tra. http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

ngoài ra, giải pháp lý tưởng sẽ là nếu khách hàng của bạn không bỏ phiếu cho kết quả liên tục, mà thay vào đó bạn sẽ đẩy dữ liệu mới và thay đổi khi nào và nếu có. Nó sẽ nhanh hơn và tải ít hơn trên máy chủ. nếu bạn đang sử dụng gui dựa trên web, bạn nên xem xét APE http://ape-project.org/ hoặc các dự án tương tự khác.


Thật không may, đây là một kẻ giết người hiệu suất. Tổng kiểm tra được tạo thành bằng cách băm tất cả các hàng một . Từ các tài liệu: "Tính toán theo hàng này là những gì bạn nhận được với mệnh đề EXTENDED, với InnoDB và tất cả các công cụ lưu trữ khác ngoài MyISAM và với các bảng MyISAM không được tạo bằng mệnh đề
CHECKSUM

1

Nếu bạn chủ yếu thêm vào một bảng, bạn có thể kết nối với AUTO_INCREMENT như một biện pháp cập nhật.

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

Nhưng tôi muốn tham khảo một nguồn otside như bộ đếm trong Memcached mà bạn sẽ tăng lên mỗi khi bạn thay đổi thứ gì đó trong cơ sở dữ liệu.


0

Bạn có thể thử làm như sau:

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

Điều này trả về một số tăng với mỗi bản cập nhật bảng, theo dõi nó sẽ cho phép phát hiện thay đổi.

Lưu ý quan trọng: giá trị được thay đổi ngay sau CẬP NHẬT, không phải sau CAM KẾT. Vì vậy, bạn có thể không thấy các thay đổi nếu các sửa đổi được thực hiện trong một giao dịch khác không hoàn thành.


0

Câu trả lời này không liên quan gì đến các phiên bản hoặc loại cơ sở dữ liệu mysql, tôi muốn biết liệu các câu lệnh cập nhật có thực hiện thay đổi VÀ để thực hiện điều này trong mã php của tôi không ..

  1. Tạo một bảng giả với một bản ghi và một trường mà tôi sẽ truy vấn để lấy giá trị của current_timestamp của mysql.

  2. Để bảng dữ liệu được cập nhật, đã thêm trường dấu thời gian và sử dụng tùy chọn mysql "TRÊN CẬP NHẬT CURRENT_TIMESTAMP"

  3. So sánh # 1 và # 2

Điều này sẽ không hoạt động 100% thời gian nhưng đối với ứng dụng của tôi, đó là một giải pháp đơn giản và tuyệt vời. Hy vọng điều này sẽ giúp ai đó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.