2012-03-06 9 views
7

विकास डेटाबेस में, मेरे पास सभी तालिकाओं पर phpMyAdmin ट्रैकिंग सक्षम है। यह टेबल के ढांचे में किए गए सभी परिवर्तनों को लॉग करता है (इस मामले में मुझे डेटा ट्रैकिंग में दिलचस्पी नहीं है।) अब तक बहुत अच्छा है।phpMyAdmin की ट्रैकिंग तंत्र का उपयोग कर डेटाबेस माइग्रेट करना

मैं जो करना चाहता हूं, वह एक विशिष्ट संस्करण (या एक तिथि भी काम करेगा) से किए गए परिवर्तनों के साथ, सभी ट्रैक किए गए तालिकाओं के लिए एक रिपोर्ट लेना है ताकि मैं अपने उत्पादन पर परिणामी एसक्यूएल चला सकूं डेटाबेस, नए संस्करणों में अपग्रेड करते समय, और यह सुनिश्चित कर लें कि डेटाबेस समान हैं, जो मैन्युअल हैंडलिंग के साथ आने वाली त्रुटियों की चिंता के बिना।

हालांकि, ऐसा कोई कार्य नहीं है जो मुझे मिल सकता है जो ऐसी रिपोर्ट उत्पन्न करता है। सभी ट्रैकिंग रिपोर्ट अलग-अलग तालिकाओं के लिए हैं, और यदि मुझे सभी तालिकाओं (20+) के माध्यम से क्लिक करना है, तो यह इस फ़ंक्शन का लाभ उठाता है। सभी तालिकाओं में बदलाव नहीं होता है, लेकिन मैं जो बदल रहा हूं उसका ट्रैक रखना नहीं चाहता हूं, यही वह है जो मैं चाहता हूं कि phpMyAdmin मेरे लिए करे।

मैंने पीएमएट्रैकिंग टेबल के खिलाफ अपनी खुद की क्वेरी बनाने की कोशिश की है जहां परिवर्तन संग्रहीत किए जाते हैं, और आंशिक सफलता होती है। समस्या यह है कि एक संस्करण के लिए सभी परिवर्तन एक बीएलओबी के रूप में संग्रहीत किए जाते हैं, और प्रत्येक नए संस्करण के साथ एक ड्रॉप टेबल/तालिका तालिका बनाते हैं, और मैं उत्पादन डीबी पर टेबल नहीं छोड़ सकता क्योंकि वहां डेटा है (मैं हूं प्रत्येक बार डेटाबेस को पुन: प्रयास नहीं करते, केवल वृद्धिशील परिवर्तन जोड़ते हैं)। मैं बस संरचना को अपग्रेड करना चाहता हूं, और एकमात्र बार जब मैं टेबल स्टेटमेंट बनाना चाहता हूं तो मैं वास्तव में डेटाबेस में एक नई तालिका बना देता हूं। तो मैंने सोचा कि मैं उन्हें एसक्यूएल के साथ फ़िल्टर कर सकता हूं, लेकिन फिर इसे एक ब्लॉग के रूप में संग्रहीत किया जाता है, और फिर मुझे ब्लॉब टेक्स्ट के साथ पार्स और गड़बड़ करना होगा जो अत्यधिक जटिल लगता है।

  • एक स्वचालित ट्रैकिंग प्रणाली/कार्यप्रवाह है कि सभी संरचना अद्यतन लॉग करता है, और एक संस्करण से पूरे डेटाबेस के लिए वृद्धिशील एसक्यूएल रिपोर्ट बना सकते हैं:

    तो, एक सारांश के रूप में, यह मैं क्या देख रहा हूँ है या समय में बिंदु।

  • मैं किसी भी अतिरिक्त तृतीय पक्ष एप्लिकेशन का उपयोग नहीं करने के लिए पसंद करते हैं, संभव

इसके अलावा, अगर, मैं कार्यप्रवाह पर टिप्पणी प्यार होता, अगर कोई उपाय हैं (मैं phpMyAdmin या MySQL केवल उपयोग करना चाहते हैं) बेहतर एक का। किसी भी मदद की सराहना की।

+0

मैं भी इस का जवाब जानना चाहता हूं। –

+0

प्रश्न का एक उपहार है, इसलिए एक उत्तर अतिरिक्त प्रतिष्ठा प्राप्त करेगा। –

+0

डीबीए के लिए phpmyadmin का उपयोग करना अजीब विचार है, –

उत्तर

0

मैं एसक्यूएल उपकरणों के साथ भी परिचित नहीं हूँ, इसलिए मैं कुछ भी करने की अनुशंसा नहीं कर सकते हैं वहाँ मदद करने के लिए है, लेकिन मैं कोशिश करते हैं और एक कस्टम वर्कफ़्लो के साथ मदद कर सकते हैं ...

  1. एक मेज structure_log
  2. बनाएं जिसका नाम
  3. print_stucture.php नामक एक PHP स्क्रिप्ट बनाएं जो सर्वर पर किसी भी फ़ाइल को आप जो भी जानकारी चाहते हैं उसे प्रिंट करता है, फ़ाइल को टाइमस्टैम्प के रूप में सहेजता है (यह आपका संस्करण नंबर होगा), और struct_log तालिका
  4. में नाम सहेजता है एक crontab जो print_structure.php चलाता है हालांकि अक्सर आप
  5. चाहते हैं
  6. delete_dups.php नामक एक PHP स्क्रिप्ट बनाएं जो आपके struct_log तालिका से पिछले दो रिकॉर्ड्स को पकड़ता है, उन दो फ़ाइलों की तुलना करता है, और यदि वे समान हैं (संरचनाओं में कोई परिवर्तन नहीं दर्शाते हैं), नवीनतम टाइमस्टैम्प (फ़ाइल नाम) के साथ एक को हटा देता है और निकालता है कि structure_log तालिका
  7. से रिकॉर्ड एक crontab कि delete_dups.php आधा जितनी बार चलाता है एक चलाता है कि print_structure.php

यह आपके सर्वर पर एक संस्करण फ़ोल्डर कर देगा के रूप में बनाएँ। आप मैन्युअल रूप से print_structure चला सकते हैं।php स्क्रिप्ट जब भी आप चाहते हैं और अपने सर्वर फ़ोल्डर में नवीनतम संस्करण लॉग के मुकाबले इसकी तुलना करें, यह देखने के लिए कि क्या आपका डेटाबेस आपने अभी इसे चलाया है, वही है जब संस्करण की जांच आखिरी बार चलती थी।

1

मुझे नहीं पता कि आप phpMyAdmin का उपयोग करके इस समस्या को कैसे हल कर सकते हैं, लेकिन ऐसे अन्य उपकरण भी हैं जो आपको ढूंढने वाले प्रभाव को प्राप्त करने में आपकी सहायता कर सकते हैं। Liquibase उनमें से एक है। मैंने इसे अतीत में कुछ बार इस्तेमाल किया है और यह बहुत अच्छा था। इसे लटका पाने में थोड़ा सा लगता है, लेकिन मुझे लगता है कि यह आपकी मदद कर सकता है।

3

"pma_tracking" तालिका PMA_Tracker class की getTrackedData विधि में स्थित है ब्लॉब क्षेत्र को पार्स, libraries/Tracker.class.php स्रोत फ़ाइल में के लिए एल्गोरिथ्म।
उस कोड से शुरू करने से, मैंने "pma_tracking" तालिका से सभी डेटा परिभाषा विवरण ("ड्रॉप तालिका" कथन को छोड़कर) निकालने के लिए एक सरल PHP स्क्रिप्ट लिखी है।
उदाहरण के लिए, कि आप के बाद से संस्करण "1" "परीक्षण" डेटाबेस के सभी तालिकाओं के सभी परिवर्तनों की सूची प्राप्त करना चाहते हैं लगता है:

<?php 

$link = mysqli_init(); 

// Adjust hostname, username, password and db name before use! 
$db = mysqli_real_connect($link, "localhost", "myuser", "mypass", "phpmyadmin") 
     or die(mysqli_connect_error()); 

// Adjust also target db name and tracking version 
$db_name = "test"; 
$version = "1"; 

$sql = "SELECT schema_sql FROM pma_tracking 
     WHERE db_name='{$db_name}' AND version>='{$version}' 
     ORDER BY version,date_created"; 
$result = mysqli_query($link, $sql) or die(mysqli_error($link)); 
while ($myrow = mysqli_fetch_assoc($result)) { 
    $log_schema_entries = explode('# log ', $myrow['schema_sql']); 
    foreach ($log_schema_entries as $log_entry) { 
     if (trim($log_entry) != '') { 
      $statement = trim(strstr($log_entry, "\n")); 
      if (substr($statement, 0, 11) != "DROP TABLE ") { 
       echo "{$statement}\n"; 
      } 
     } 
    } 
} 

?> 

एक फ़ाइल पर स्क्रिप्ट उत्पादन पुनः निर्देशित करके, आप लक्ष्य (उदाहरण के लिए उत्पादन) डेटाबेस पर स्कीमा परिवर्तनों को दोहराने के लिए आवश्यक सभी कथन (लगभग) के साथ एक SQL कमांड फ़ाइल प्राप्त करेंगे; इस फ़ाइल "-f" (शक्ति) MySQL विकल्प निर्दिष्ट करने के द्वारा निष्पादित किया जाना चाहिए:

-f, यहां तक ​​कि जारी --force अगर हम एक एसक्यूएल त्रुटि मिलती है।

ऐसा करके, MySQL सभी "तालिका में पहले से ही मौजूद है" त्रुटि है कि हर बार है कि एक मौजूदा तालिका के लिए एक CREATE TABLE बयान का सामना करना पड़ा है केवल टेबल अभी भी does'nt कि में मौजूद बनाने फेंक दिया जाएगा, इस प्रकार पर ध्यान नहीं देगा लक्ष्य डेटाबेस।
दृष्टिकोण इस तरह की स्पष्ट रूप से कुछ कमियां भी हैं:

  1. सभीDROP TABLE आदेशों को अनदेखा किया जाएगा (न केवल स्वचालित रूप से phpMyAdmin से डाला गया है), इसलिए यदि आप स्रोत डेटाबेस में एक मेज नष्ट कर दिया है, कि लक्ष्य डेटाबेस में तालिका हटाई नहीं जाएगी।
  2. सभी स्क्रिप्ट त्रुटियों को अनदेखा कर दिया जाएगा, इसलिए यह 100% किफायती नहीं हो सकता है।

सलाह का एक अंतिम शब्द: आगे बढ़ने से पहले हमेशा अपने लक्षित डेटाबेस का पूरा बैकअप लें!

+0

वैकल्पिक समाधान के रूप में, आपको [MySQLdiff] (http://www.mysqldiff.org/) का उपयोग करने पर विचार करना चाहिए। –

0

मैं कुछ भी है कि दो डेटाबेस के बीच एक वृद्धिशील diff बनाता है, लेकिन यहाँ स्क्रिप्ट मैं दो MySQL डेटाबेस की तुलना करने के लिए उपयोग की जरूरत नहीं है:

<?php 
//------------------------------------------------------------------------------ 
// Define the variables we'll be using. 
//------------------------------------------------------------------------------ 
$db1_con = NULL; 
$db1_constraints = array(); 
$db1_dbname = 'db1'; 
$db1_host = 'localhost'; 
$db1_password = 'password1'; 
$db1_tables = array(); 
$db1_username = 'username1'; 

$db2_con = NULL; 
$db2_constraints = array(); 
$db2_dbname = 'db2'; 
$db2_host = '123.123.123.123'; 
$db2_password = 'password2'; 
$db2_tables = array(); 
$db2_username = 'username2'; 

//------------------------------------------------------------------------------ 
// Connect to the databases. 
//------------------------------------------------------------------------------ 
try{ 
    $db1_con = new PDO("mysql:host=$db1_host;dbname=information_schema", $db1_username, $db1_password); 
    $db1_con->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); // Try to use the driver's native prepared statements. 
    $db1_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Let's use exceptions so we can try/catch errors. 
}catch(PDOException $e){ 
    echo "<p>Connection failed for $db1_host: " . $e->getMessage() . '</p>'; 
    exit; 
} 

try{ 
    $db2_con = new PDO("mysql:host=$db2_host;dbname=information_schema", $db2_username, $db2_password); 
    $db2_con->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); // Try to use the driver's native prepared statements. 
    $db2_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Let's use exceptions so we can try/catch errors. 
}catch(PDOException $e){ 
    echo "<p>Connection failed for $db2_host: " . $e->getMessage() . '</p>'; 
    exit; 
} 

if (NULL !== $db1_con && NULL !== $db2_con){ 
    echo "<h2>Column Analysis</h2>"; 
    $sql = 'SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION'; 
    $statement1 = $db1_con->prepare($sql); 
    $statement1->bindValue(1, $db1_dbname); 

    $statement2 = $db2_con->prepare($sql); 
    $statement2->bindValue(1, $db2_dbname); 

    if (TRUE === $statement1->execute()){ 
     while ($row = $statement1->fetch(PDO::FETCH_ASSOC)){ 
      $db1_tables[$row['TABLE_NAME']][$row['COLUMN_NAME']] = array(); 
      foreach ($row AS $key => $value){ 
       $db1_tables[$row['TABLE_NAME']][$row['COLUMN_NAME']][$key] = $value; 
      } 
     } 
    } 

    if (TRUE === $statement2->execute()){ 
     while ($row = $statement2->fetch(PDO::FETCH_ASSOC)){ 
      $db2_tables[$row['TABLE_NAME']][$row['COLUMN_NAME']] = array(); 
      foreach ($row AS $key => $value){ 
       $db2_tables[$row['TABLE_NAME']][$row['COLUMN_NAME']][$key] = $value; 
      } 
     } 
    } 

    foreach ($db1_tables AS $table => $info){ 
     if (!isset($db2_tables[$table])){ 
      echo "<p>Table <strong>$table</strong> does not exist in the SECOND database!</p>"; 
     }else{ 
      foreach ($info AS $column => $data){ 
       if (!isset($db2_tables[$table][$column])){ 
        echo "<p>Column <strong>$column</strong> does not exist in table <strong>$table</strong> in the SECOND database!</p>"; 
       }else{ 
        if (count($data)){ 
         foreach ($data AS $key => $value){ 
          if ($db1_tables[$table][$column][$key] !== $db2_tables[$table][$column][$key]){ 
           echo "<p>Column <strong>$column</strong> in table <strong>$table</strong> has differing characteristics for <strong>$key</strong> (". $db1_tables[$table][$column][$key] ." vs. ". $db2_tables[$table][$column][$key] .")</p>"; 
          } 
         } 
        } 
       } 
      } 
     } 
    } 

    foreach ($db2_tables AS $table => $info){ 
     if (!isset($db1_tables[$table])){ 
      echo "<p>Table <strong>$table</strong> does not exist in the FIRST database!</p>"; 
     }else{ 
      foreach ($info AS $column => $data){ 
       if (!isset($db1_tables[$table][$column])){ 
        echo "<p>Column <strong>$column</strong> does not exist in table <strong>$table</strong> in the FIRST database!</p>"; 
       }else{ 
        if (count($data)){ 
         foreach ($data AS $key => $value){ 
          if ($db2_tables[$table][$column][$key] !== $db1_tables[$table][$column][$key]){ 
           echo "<p>Column <strong>$column</strong> in table <strong>$table</strong> has differing characteristics for <strong>$key</strong> (". $db2_tables[$table][$column][$key] ." vs. ". $db1_tables[$table][$column][$key] .")</p>"; 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
    echo "<h2>Constraint Analysis</h2>"; 

    $sql = 'SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION'; 
    $statement1 = $db1_con->prepare($sql); 
    $statement1->bindValue(1, $db1_dbname); 

    $statement2 = $db2_con->prepare($sql); 
    $statement2->bindValue(1, $db2_dbname); 

    if (TRUE === $statement1->execute()){ 
     while ($row = $statement1->fetch(PDO::FETCH_ASSOC)){ 
      foreach ($row AS $key => $value){ 
       $db1_constraints[$row['TABLE_NAME']][$row['COLUMN_NAME']][$key] = $value; 
      } 
     } 
    } 

    if (TRUE === $statement2->execute()){ 
     while ($row = $statement2->fetch(PDO::FETCH_ASSOC)){ 
      foreach ($row AS $key => $value){ 
       $db2_constraints[$row['TABLE_NAME']][$row['COLUMN_NAME']][$key] = $value; 
      } 
     } 
    } 

    foreach ($db1_constraints AS $table => $info){ 
     foreach ($info AS $column => $data){ 
      if (isset($db2_constraints[$table][$column])){ 
       if (count($data)){ 
        foreach ($data AS $key => $value){ 
         if ('CONSTRAINT_NAME' !== $key && $db1_constraints[$table][$column][$key] !== $db2_constraints[$table][$column][$key]){ 
          echo "<p>Column <strong>$column</strong> in table <strong>$table</strong> has differing characteristics for <strong>$key</strong> (". $db1_constraints[$table][$column][$key] ." vs. ". $db2_constraints[$table][$column][$key] .")</p>"; 
         } 
        } 
       } 
      }else{ 
       echo "<p>Column <strong>$column</strong> in table <strong>$table</strong> is missing a constraint in the SECOND database!</p>"; 
      } 
     } 
    } 

    foreach ($db2_constraints AS $table => $info){ 
     foreach ($info AS $column => $data){ 
      if (isset($db1_constraints[$table][$column])){ 
       if (count($data)){ 
        foreach ($data AS $key => $value){ 
         if ('CONSTRAINT_NAME' !== $key && $db2_constraints[$table][$column][$key] !== $db1_constraints[$table][$column][$key]){ 
          echo "<p>Column <strong>$column</strong> in table <strong>$table</strong> has differing characteristics for <strong>$key</strong> (". $db2_constraints[$table][$column][$key] ." vs. ". $db1_constraints[$table][$column][$key] .")</p>"; 
         } 
        } 
       } 
      }else{ 
       echo "<p>Column <strong>$column</strong> in table <strong>$table</strong> is missing a constraint in the FIRST database!</p>"; 
      } 
     } 
    } 
} 
?> 

संपादित कोड है कि बाधाओं में मतभेद के रूप में अच्छी तरह से पता चलता जोड़ने के लिए।

+0

परिणाम इस स्क्रिप्ट का डेटाबेस डेटाबेस माइग्रेट करने के लिए उपयोग किया जा सकता है? –

+0

जैसा कि अभी है, नहीं। आपको SQL कमांड जेनरेट करने के लिए कुछ और कोड लिखना होगा। आपको जो जानकारी चाहिए वह वही है ough (तालिका के नाम, कॉलम नाम, कॉलम प्रकार, आदि) संबंध डेटा प्राप्त करने के लिए आपको KEY_COLUMN_USAGE तालिका से पूछताछ करने की आवश्यकता होगी। –

+0

@EmanuilRusev - क्या आप "डेटाबेस माइग्रेट करें" द्वारा अपना क्या मतलब स्पष्ट कर सकते हैं? मेरे लिए इसका मतलब है कि आप एक डेटाबेस से दूसरे सर्वर पर संपूर्ण डेटाबेस संरचना (और सभी डेटा) की प्रतिलिपि बनाना चाहते हैं। अगर मैं ऐसा करने जा रहा था तो मैं सिर्फ mysql डंप या phpMyAdmin की मौजूदा कार्यक्षमता का उपयोग करता हूं। मैंने जो स्क्रिप्ट यहां दिखाया है वह वह है जो मैं उपयोग करता हूं जब मैं विकास से उत्पादन में परिवर्तन कर रहा हूं। मैं नहीं चाहता कि मेरी स्क्रिप्ट एक उत्पादन बॉक्स में स्वचालित रूप से कुछ भी करे, मैं बस यह कहना चाहता हूं कि अलग क्या है, इसलिए मैं यह निर्धारित कर सकता हूं कि इसे उत्पादन वातावरण में पोर्ट किया जाना चाहिए या नहीं। –

0

मैं MySQL Workbench साथ कुछ सफलता मिली है:

आयात (रिवर्स इंजीनियर) कार्यक्षेत्र में अपने देव डेटाबेस। आप या तो अपनी स्कीमा को SQL फ़ाइल में निर्यात करके और इसे वर्कबेंच में लोड करके कर सकते हैं, या वर्कबेंच को सीधे सर्वर से स्कीमा प्राप्त होगा।

अगला, "सिंक्रनाइज़ मॉडल" विकल्प के साथ अपनी diff फ़ाइल जेनरेट करें। आप उत्पादन डेटाबेस का चयन करते हैं, फिर किन सारणी सिंक करने के लिए, और वर्कबेंच एक SQL फ़ाइल उत्पन्न करता है जिसे आप दोनों मॉडलों को सिंक करने के लिए चला सकते हैं।

सावधानी का एक शब्द: पहली बार, कुछ स्पष्ट रूप से असीमित परिवर्तन होंगे जबकि डीबी को वर्कबेंच "स्टाइल" में अपडेट किया जाएगा। बाद के अपडेट के लिए, टूल अपेक्षाकृत भरोसेमंद है, हालांकि मैं कभी भी अपने उत्पादन डीबी पर स्वचालित उपकरण नहीं दे सकता ;-)

त्रुटियों के लिए हमेशा SQL फ़ाइल की जांच करें, कुछ मामलों में, कॉलम छोड़कर फिर एक और जोड़ना एक ही नाम के लेकिन अलग-अलग प्रकार एक परिवर्तित कॉलम उत्पन्न करेंगे जो असफल हो जाएगा।

संबंधित मुद्दे