it-swarm.asia

أسرع طريقة للتحقق مما إذا كان جدول InnoDB قد تغير

طلبي مكثف للغاية لقاعدة البيانات. حاليًا ، أنا أشغّل MySQL 5.5.19 وأستخدم MyISAM ، لكنني بصدد الترحيل إلى InnoDB. المشكلة الوحيدة المتبقية هي أداء المجموع الاختباري.

طلبي يفعل حوالي 500-1000 CHECKSUM TABLE عبارات في الثانية في أوقات الذروة ، لأن عملاء واجهة المستخدم الرسومية يقومون باستقصاء قاعدة البيانات باستمرار للتغييرات (إنه نظام مراقبة ، لذا يجب أن يكون سريع الاستجابة وسريع الاستجابة).

مع MyISAM ، هناك مجموعات اختبارية مباشرة يتم حسابها مسبقًا على تعديل الجدول وهي سريعة جدًا. ومع ذلك ، لا يوجد شيء من هذا القبيل في InnoDB. وبالتالي، CHECKSUM TABLE بطيء جدا.

آمل أن أتمكن من التحقق من وقت آخر تحديث للجدول ، للأسف ، هذا غير متوفر في InnoDB أيضًا. أنا عالق الآن ، لأن الاختبارات أظهرت أن أداء التطبيق ينخفض ​​بشكل كبير.

هناك ببساطة العديد من أسطر التعليمات البرمجية التي تقوم بتحديث الجداول ، لذا فإن تنفيذ المنطق في التطبيق لتسجيل تغييرات الجدول أمر غير وارد.

هل هناك طريقة سريعة لاكتشاف التغييرات في جداول InnoDB؟

22
Jacket

أعتقد أنني وجدت الحل. لبعض الوقت كنت أبحث في 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';

كنت سأقوم بترقية خوادمي إلى خادم بيركونا على أي حال ، لذا فإن هذا الربط ليس مشكلة بالنسبة لي. تعد إدارة المئات من المشغلات وإضافة الحقول إلى الجداول بمثابة ألم كبير لهذا التطبيق ، لأنه متأخر جدًا في التطوير.

هذه هي وظيفة 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")); 

آمل أن يوفر هذا بعض المشاكل للآخرين الذين يعانون من نفس المشكلة.

3
Jacket

بالنسبة للجدول 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 بتوقيت شرق الولايات المتحدة

صاحب العمل الخاص بي (شركة استضافة DB/Wweb) لديه عميل مع 112000 من جداول 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 بتوقيت شرق الولايات المتحدة

عندما يتعلق الأمر باسترداد التاريخ والوقت للملف ، فإن ls لديه --time-style اختيار:

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

يمكنك مقارنة الطابع الزمني للملف مقابل UNIX_TIMESTAMP (NOW ()) .

15
RolandoMySQLDBA

يجب عليك التحديث إلى Mysql v5.6 + في هذا الإصدار الذي يدعمه أيضًا Innodb لجدول المجموع الاختباري. http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

بخلاف ذلك ، فإن الحل المثالي سيكون إذا لم يكن عميلك يستقصي النتيجة باستمرار ، ولكن بدلاً من ذلك ، يمكنك دفع البيانات الجديدة والمتغيرة متى كانت متاحة. سيكون أسرع وأقل حمولة على الخادم. إذا كنت تستخدم واجهة المستخدم الرسومية المستندة إلى الويب ، فيجب أن تنظر في APE http://ape-project.org/ أو مشاريع أخرى مماثلة.

1
Gamesh

إذا كنت تضيف إلى جدول في الغالب ، يمكنك ربط AUTO_INCREMENT كمقياس للتحديث.

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

لكنني أفضل الإشارة إلى مصدر otside مثل عداد في Memcached والذي ستزداد في كل مرة تقوم فيها بتغيير شيء ما في قاعدة البيانات.

1
sanmai

هذه الإجابة لا علاقة لها بإصدارات قاعدة بيانات mysql أو أنواعها ، أردت أن أعرف ما إذا كانت بيانات التحديث تقوم بإجراء تغييرات والقيام بذلك في كود php الخاص بي ..

  1. إنشاء جدول وهمي بسجل واحد وحقل واحد يمكنني الاستعلام عنه للحصول على قيمة mys_tl الحالية_timestamp.

  2. إلى جدول البيانات الذي يتم تحديثه ، أضف حقل ختم زمني واستخدم خيار الخلية "ON UPDATE CURRENT_TIMESTAMP"

  3. مقارنة بالرقم 1 والرقم 2

لن يعمل هذا 100 ٪ من الوقت ولكن بالنسبة إلى طلبي كان حلًا بسيطًا ورائعًا. آمل أن يساعد هذا شخص ما

0
Steve Padgett

يمكنك محاولة القيام بما يلي:

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

يؤدي هذا إلى إرجاع رقم يزيد مع كل تحديث للجدول ، وتتبعه سيسمح لكشف التغيير.

ملاحظة مهمة: يتم تغيير القيمة مباشرة بعد التحديث ، وليس بعد COMMIT. لذلك قد لا ترى التغييرات إذا تم إجراء التعديلات داخل معاملة أخرى لم تنته.

0
Romuald Brunet