2012-03-06 3 views
7

В базе данных разработки у меня есть phpMyAdmin Tracking включен во всех таблицах. Он регистрирует все изменения, которые я вношу в структуры таблиц (в этом случае меня не интересует отслеживание данных). Пока все хорошо.Перенастройка баз данных с помощью механизма отслеживания phpMyAdmin

То, что я хочу сделать, это вывести отчет для ВСЕХ отслеживаемых таблиц с изменениями, сделанными из определенной версии (или датой, даже работающей), чтобы я мог запустить полученный SQL на моем производстве базы данных, при обновлении до новых версий и убедитесь, что базы данных идентичны, без беспокойства об ошибках, возникающих при ручной обработке этого.

Однако нет никакой функции, которую я могу найти, которая генерирует такой отчет. Все отчеты отслеживания предназначены для отдельных таблиц, и если мне нужно щелкнуть по всем таблицам (20+), это уберет преимущество этой функции. Все таблицы не меняются, но я не хочу отслеживать, что изменилось, вот что я хочу сделать phpMyAdmin для меня.

Я попытался сделать свой собственный запрос против таблицы pma_tracking, где изменения сохранены и имели частичный успех. Проблема состоит в том, что все изменения для одной версии сохраняются как один BLOB, и с каждой новой версией выполняется оператор DROP TABLE/CREATE TABLE, и я не могу отбросить таблицы на производственном db, поскольку там есть данные (я не воссоздавая базу данных каждый раз, добавляя только дополнительные изменения). Я просто хочу обновить структуру, и единственный раз, когда я хочу, чтобы инструкции CREATE TABLE были, когда я фактически создаю новую таблицу в базе данных. Поэтому я подумал, что могу отфильтровать их с помощью SQL, но затем он хранится в виде блога, а затем мне придется разбираться и смешивать текст blob, который кажется слишком сложным.

Итак, как итог, это то, что я ищу:

  • Автоматизированная система слежения/документооборота, вошедшего все обновления структуры, и может создавать инкрементные отчеты SQL для всей базы данных из версии или момент времени.
  • Я предпочел бы не использовать какие-либо дополнительные приложения сторонних (я хотел бы использовать PhpMyAdmin или MySQL только), если это возможно

Кроме того, я хотел бы комментарии на рабочем процессе, если кто-то есть идеи лучшего. Любая помощь оценивается.

+0

Я также хотел бы узнать ответ на этот вопрос. –

+0

Вопрос имеет щедрость, поэтому ответ получит дополнительную репутацию. –

+0

Странная идея использовать phpmyadmin для dba, –

ответ

0

Я не слишком хорошо знаком с инструментами SQL, так что я ничего не могу рекомендовать, чтобы помочь вам, но я могу попытаться помочь с настраиваемым рабочим процессом ...

  1. Создать таблицу с именем structure_log
  2. Создайте PHP-скрипт с именем print_stucture.php, который печатает любую информацию, которую вы хотите сохранить на сервере, сохраняет файл как временную метку (это будет ваш номер версии) и сохраняет имя в таблице struct_log
  3. Создать crontab, который работает print_structure.php, но часто вы хотите
  4. Создайте PHP-скрипт с именем delete_dups.php, который захватывает последние две записи из вашей таблицы structure_log, сравнивает эти два файла, и если они одинаковы (не представляют никаких изменений в структурах), удаляет тот, у которого самая последняя отметка времени (имя файла) и удаляет эту запись из таблицы structure_log
  5. Создать кронтаб, который работает delete_dups.php половины так часто, как тот, который работает print_structure.php

Это позволит сделать папку управления версиями на вашем сервере. Вы можете вручную запустить print_structure.php каждый раз, когда вы захотите, и сравните его с последней версией журнала, который у вас есть в вашей папке сервера, чтобы узнать, была ли ваша база данных, на которой вы ее запускали, такая же, как в последний раз, когда была проверена проверка версии.

1

Я не знаю, как вы могли бы решить эту проблему, используя phpMyAdmin, но есть и другие инструменты, которые могут помочь вам добиться эффекта, который вы ищете. Liquibase является одним из них. Я использовал его несколько раз в прошлом, и это было очень хорошо. Потребуется немного, чтобы понять это, но я думаю, что это может вам помочь.

3

Алгоритм разбора BLOB поле «pma_tracking» стол расположен в getTrackedData способе PMA_Tracker class, в libraries/Tracker.class.php исходном файле.
Начиная с этого кода, я написал простой PHP-скрипт, чтобы извлечь все инструкции определения данных (кроме операторов «DROP TABLE») из таблицы «pma_tracking».
Например, предположим, что вы хотите получить список всех изменений всех таблиц базы данных «тест», начиная с версии «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 Продолжить, даже если мы получаем ошибку SQL.

Поступая таким образом, MySQL будет игнорировать все «Таблица уже существует» ошибку, которая будет отброшена каждый раз, когда CREATE TABLE заявление для существующей таблицы встречается, таким образом, создавая только таблицы, которые все еще существуют в does'nt целевой базы данных.
Такой подход, очевидно, имеет некоторые недостатки:

  1. ВСЕ в DROP TABLE команды будут игнорироваться (не только те, автоматически подставляется из PhpMyAdmin), поэтому, если вы удалили таблицу в исходной базе данных, что таблица не будет удалена в целевой базе данных.
  2. ВСЕ ошибки сценария будут проигнорированы, поэтому он не может быть на 100% доступным.

Последнее словосочетание: всегда делайте полную резервную копию своей целевой базы данных, прежде чем продолжить!

+0

В качестве альтернативного решения вам следует рассмотреть возможность использования [MySQLdiff] (http://www.mysqldiff.org/). –

0

У меня нет ничего, что создает добавочную различий между двумя базами данных, но вот сценарий я использую для сравнения двух баз данных 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>"; 
      } 
     } 
    } 
} 
?> 

Edited добавить код, который показывает различия в ограничениях, а также.

+0

Может ли результат этого сценария использовать для миграции базы данных? –

+0

Как сейчас, нет. Вам нужно будет написать еще один код для генерации SQL-команд. Вся необходимая вам информация ough (имена таблиц, имена столбцов, типы столбцов и т. д.). Чтобы получить данные отношений, вам необходимо запросить таблицу KEY_COLUMN_USAGE. –

+0

@EmanuilRusev - можете ли вы пояснить, что вы подразумеваете под «мигрировать базу данных»? Для меня это означает, что вы хотите скопировать всю структуру базы данных (и все данные) с одного сервера на другой. Если бы я собирался сделать это, я бы просто использовал mysql dump или, возможно, существующую функциональность phpMyAdmin. Сценарий, который я показал здесь, - это то, что я использую, когда я развертываю изменения от разработки до производства. Я не хочу, чтобы мой скрипт делал что-либо автоматически в окне производства, я просто хочу, чтобы он рассказал мне, что изменилось, поэтому я могу определить, нужно ли его переносить в производственную среду. –

0

Я имел некоторый успех с MySQL Workbench:

Import (перепроектирует) базы данных Dev в верстак. Вы можете сделать это, экспортировав вашу схему в файл SQL и загрузив ее в workbench, или workbench получит схему непосредственно с сервера.

Затем создайте файл diff с параметром «Синхронизировать модель». Вы выбираете производственную базу данных, затем таблицы для синхронизации, а workbench генерирует файл SQL, который вы можете запустить для синхронизации обеих моделей.

Осторожно: в первый раз, вероятно, будет довольно много видимых изменений, пока БД обновляется до «стиля» рабочего стола. Для последующих обновлений инструмент довольно надежный, хотя я бы никогда не позволял автоматическому инструменту иметь свободный диапазон над моей производственной БД ;-)

Всегда проверяйте файл SQL на наличие ошибок, в некоторых случаях удаляя столбец, а затем добавляя другой с тем же именем, но с другим типом будет генерировать столбец alter, который будет терпеть неудачу.

 Смежные вопросы

  • Нет связанных вопросов^_^