यह जांचने का सबसे तेज़ तरीका कि क्या InnoDB तालिका बदल गई है


22

मेरा आवेदन बहुत डेटाबेस गहन है। वर्तमान में, मैं MySQL 5.5.19 चला रहा हूं और MyISAM का उपयोग कर रहा हूं, लेकिन मैं InnoDB की ओर पलायन की प्रक्रिया में हूं। केवल एक समस्या है चेकसम प्रदर्शन।

मेरा आवेदन CHECKSUM TABLEपीक समय में प्रति सेकंड लगभग 500-1000 स्टेटमेंट करता है , क्योंकि क्लाइंट जीयूआई डेटाबेस को लगातार बदलावों के लिए सर्वेक्षण कर रहा है (यह एक निगरानी प्रणाली है, इसलिए बहुत ही संवेदनशील और तेज़ होना चाहिए)।

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

कोशिश तो करो !!!

UPDATE 2011-12-21 20:04 EDT

मेरे नियोक्ता (DB / Wweb होस्टिंग कॉमनी) के पास 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}'

यह टाइमस्टैम्प ओएस से है। आप इस पर गलत नहीं कर सकते।

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

UPDATE 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 (अब ()) के विरुद्ध फ़ाइल के टाइमस्टैम्प की तुलना कर सकते हैं ।


क्या आप वाकई गलत w / idb moddate नहीं जा सकते हैं? एक बदलाव सिर्फ मेमोरी में बफ़र पूल में रह सकता है और अभी तक डिस्क में फ्लश नहीं किया गया है।
atxdba

6
उत्तर के लिए धन्यवाद, लेकिन जैसा कि मैंने कहा, info_schema.tables में update_time, InnoDB तालिकाओं के लिए NULL है। इसके अलावा, मुझे यकीन नहीं है कि innodb_max_dirty_pages_pct = 0 एक अच्छा विचार है, क्योंकि यह प्रदर्शन का बलिदान करेगा ... मैं ट्रिगर्स के साथ एक समाधान के बारे में सोच रहा था, प्रत्येक देखे जाने वाले तालिकाओं में से एक संदर्भ तालिका में एक यादृच्छिक मूल्य डालने के लिए, लेकिन फिर मुझे इसके लिए प्रति तालिका केवल 3 ट्रिगर की आवश्यकता होगी ...
जैकेट

इसके अलावा information_schema.tables से चयन भी धीमी गति से होता है ... मैं एक तालिका की जांच करने के लिए लगभग 300ms लेता हूं। MyISAM टेबल पर लाखों लोगों के साथ "चेचक टेबल" की तुलना करने के लिए, लाइव चेकसम सक्षम के साथ लाखों पंक्तियों में एक मील के पत्थर से कम समय लग रहा है।
जैकेट

2
फाइल सिस्टम की जांच के लिए +1, जब तक कि बफर फ्लशिंग नियमित पर्याप्त (मोटे तौर पर एक बार प्रति सेकंड डिफ़ॉल्ट है), तो यह समय स्टाम्प सुंदर, सटीक, और शायद अच्छा ज्यादातर मामलों के लिए पर्याप्त हो जाएगा ... है
डेव Rix

1
शायद यह एक स्थानीय डेटाबेस के लिए ठीक है, लेकिन मेरे पास कई दूरस्थ दास हैं, इसलिए यह काम नहीं कर रहा है ...
जैकेट

3

मुझे लगता है कि मैंने इसका हल ढूंढ लिया है। कुछ समय से मैं अपने MySQL सर्वर को बदलने के लिए Percona Server को देख रहा था, और अब मुझे लगता है कि इसके लिए एक अच्छा कारण है।

Percona सर्वर INNODB_TABLE_STATS जैसी कई नई INFORMATION_SCHEMA तालिकाएँ प्रस्तुत करता है, जो मानक 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 + से अपडेट करना चाहिए। उस संस्करण में चेकसम टेबल के लिए इनोडब का भी समर्थन है। http://dev.mysql.com/doc/refman/5.6/en/checksum-table.html

अन्य तब, आदर्श समाधान यह होगा कि यदि आपका ग्राहक परिणाम के लिए लगातार मतदान नहीं कर रहा है, लेकिन इसके बजाय आप नए और परिवर्तित डेटा को धक्का दे रहे हैं जब और यदि यह उपलब्ध था। यह तेज़ होगा और सर्वर पर कम लोड होगा। यदि आप वेब आधारित gui का उपयोग कर रहे हैं, तो आपको APE http://ape-project.org/ या अन्य समान परियोजनाओं पर ध्यान देना चाहिए ।


दुर्भाग्य से, यह एक प्रदर्शन हत्यारा है। चेकसुम को सभी पंक्तियों को एक-एक करके हैशिंग द्वारा बनाया गया है । डॉक्स से: "यह पंक्ति-दर-पंक्ति गणना वह है जो आपको EXTENDED क्लॉज के साथ मिलती है, जिसमें InnoDB और MyISAM के अलावा अन्य सभी स्टोरेज इंजन हैं, और MyISAM टेबल्स के साथ CHECKSUM =" क्लॉज "नहीं बनाया गया है :
LSerni

1

यदि आप ज्यादातर तालिका में जोड़ रहे हैं, तो आप अपडाउनटेंस के उपाय के रूप में AUTO_INCREMENT पर हुक कर सकते हैं।

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

लेकिन मैं मेमकाटेड में एक काउंटर की तरह एक otside स्रोत को संदर्भित करना पसंद करूंगा जिसे आप डेटाबेस में कुछ बदलने पर हर बार बढ़ाएंगे।


0

आप निम्नलिखित करने की कोशिश कर सकते हैं:

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

यह एक संख्या देता है जो प्रत्येक टेबल अपडेट के साथ बढ़ता है, इसका ट्रैक रखने से परिवर्तन का पता लगाने की अनुमति मिलेगी।

महत्वपूर्ण नोट: मान एक अद्यतन के तुरंत बाद बदल दिया जाता है, COMMIT के बाद नहीं। इसलिए यदि आप बदलाव किसी अन्य लेन-देन के अंदर नहीं किए गए हैं तो बदलाव नहीं देख सकते हैं।


0

इस उत्तर का mysql डेटाबेस संस्करणों या प्रकारों से कोई लेना-देना नहीं है, मैं जानना चाहता था कि क्या अपडेट स्टेटमेंट में बदलाव किए जा रहे हैं और मेरे php कोड में ऐसा करने के लिए।

  1. एक रिकॉर्ड और एक फ़ील्ड के साथ एक डमी टेबल बनाया, जिसे मैं mysql के current_timestamp का मान प्राप्त करने के लिए क्वेरी करूँगा।

  2. अद्यतन की जा रही डेटा तालिका में, एक टाइमस्टैम्प फ़ील्ड जोड़ा और mysql विकल्प "ON UPDATE CURRENT_TIMESTAMP" का उपयोग किया

  3. # 1 और # 2 की तुलना में

यह समय के 100% काम नहीं करेगा लेकिन मेरे आवेदन के लिए यह एक सरल और महान समाधान था। आशा है कि यह किसी की मदद करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.