Версионная миграция структуры базы данных: еще один подход

Прочитал интересную и полезную статью (1) — и захотел поделиться собственным опытом. В нашей фирме за 12 лет работы с одной (своей, Oracle-ориентированной) программой у сотен клиентов накоплен богатейший материал на тему апгрейда структуры БД.

Первоначально мы предполагали, что достаточно хранить в каждой БД номер версии последнего апгрейда и накатывать скрипты инкрементально, поднимая версию до нужной. Такая методика успешно использовалась в предыдущей версии нашей программы, работавшей с СУБД Paradox. Но с СУБД Oracle все пошло не так, у каждого клиента было собственное видение, какой должна быть его БД, и рассинхронизация версий стала неизбежным злом. Привычная методика апгрейдов по версиям стала постоянно приводить к ошибкам, на которые уже никто и не обращал внимание, и рассогласование структур продолжалось несколько лет. В итоге у каждого клиента оказалась собственная, не идентичная никакой другой, структура БД, а клиентская часть программы как-то должна была с этим бороться.

В какой-то момент руководство поручило вплотную заняться проблемой апгрейдов БД ведущему программисту фирмы (мне) — человеку творческому, предпочитающему потратить больше времени, но избежать рутинной работы. И тогда был разработан инструмент, позволивший практически свести на нет различия в структурах БД у всех клиентов. Об этой технологии я и хочу рассказать мировому сообществу.



В основе новой технологии лежат три алгоритма:

— Получение XML-образа реальной БД
— Сравнение двух XML-образов и выявление различий
— Формирование скрипта на устранение различий

Пользовательский интерфейс

Визуально инструмент выглядит как окно, разделенное по горизонтали на три области:
— в левой панели — древообразная структура загруженных объектов (для краткости — «дерево»);
— в средней и правой панели — детальное описание выделенного в дереве объекта в сравниваемых структурах (эти панели я называю «панелями сравнения»).

В программу загружаются одна или две структуры — из реальной БД или из XML-файла. В дереве объектов отображается объединенная иерархия, то есть объекты, присутствующие хотя бы в одной из двух загруженных структур. Одинаковые, отличающиеся или отсутствующие с одной из сторон объекты изображаются различными значками — соответственно белыми, синими или красно-белыми (красный с той стороны, где объект отсутствует).

Над деревом по нажатию кнопки появляется или исчезает панель фильтров.

В верхней части каждой из панелей сравнения отображается источник данных — схема Oracle или файл.

Над панелями сравнения по нажатию кнопки появляется или исчезает панель опций.

Интерфейс пользователя мог бы быть и другим, это не принципиально — и, возможно, мы его переделаем в будущем — но пока это выглядит примерно так, как я описал.

Получение XML-образа реальной БД

Подключаясь к реальной БД, программа выполняет ряд SQL-запросов, получая информацию о метаданных Oracle, и полученная информация собирается в памяти программы в иерархическую объектную структуру, где каждому объекту метаданных ставится в соответствие свой узел иерархии.

При этом пользователь может наложить фильтр на типы и имена загружаемых объектов метаданных.

В общем случае загрузке подлежат структуры нескольких схем. Пользователь выбирает одну из трех опций:
— Абстрактная схема
— Конкретная схема
— Все схемы сервера

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

В случае выбора третьей опции загружаются структуры всех схем сервера, кроме стандартных (создаваемых при инсталляции Oracle и создании экземпляра БД)

«Абстрактная схема» означает, что имя основной схемы Oracle не имеет значения, так можно сравнивать между собой сходные по структуре схемы с разными именами. Практически это означает, что имя узла основной схемы получит не имя загруженной схемы, а абстрактное имя user — схему с таким именем создать нельзя (а если даже у кого-то и получится, то в этом мало смысла).

«Конкретная схема» означает, что имя основной схемы имеет значение, и ее структура может сравниваться только со структурой одноименной с ней схемы.

Дополнительные схемы сравниваются всегда с учетом имени, то есть узлы этих схем носят имя исходных схем Oracle.

Полученная объектная структура может быть сохранена в файле формата XML, который можно сразу запаковать в формате ZIP.

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

Каждый новый релиз нашей программы поставляется с таким вот образом стандартной БД в запакованном файле, чтобы на сервере клиента можно было произвести анализ различий, сравнивая реальную структуру с образом из прилагаемого файла.

Сравнение двух XML-образов и выявление различий

В основе идентификации сравниваемых узлов лежат два критерия — общий родительский узел и одинаковое имя самого узла. Имя узла используется и для сортировки дочерних узлов одного родительского узла. Поэтому именованию узлов разных типов объектов придается особое значение.

На верхнем уровне иерархии находятся узлы схем — вначале идут дополнительные схемы, отсортированные по имени, затем основная схема (напоминаю, этот узел называется или именем схемы, или словом user).

Дочерние узлы схем — группы объектов одного типа (таблицы, представления, секвенсоры, хранимые процедуры и т.д.) Имена этих узлов соответствуют их назначению: tables, views и т.д.

На третьем уровне располагаются сами объекты, имена которых должны быть уникальны в рамках своей группы.

Четвертый и далее уровни определяются типом объекта, и в дереве не отображаются. Эти уровни соответствуют объектам или их группам, хранимым и обрабатываемым в памяти программы и отображаемым на панелях сравнения при выборе соответствующего объекта третьего уровня.

Например, у таблицы есть дочерний узел columns со своими дочерними узлами, описывающими каждое поле таблицы, есть узлы triggers, constraints и т.д.

Каждый объект в памяти программы хранит признаки наличия объекта в каждой из сравниваемых структур и отличий между ними. Составные объекты сравниваются по отличиям в дочерних узлах, конечные узлы сравниваются индивидуальными для каждого типа объекта методами.

Для объектов PL/SQL (триггеров, процедур и т.д.) есть возможность запустить внешнюю утилиту для визуального сравнения текстовых данных типа Beyond Compare, WinMerge или любой другой (предполагается, что эта утилита принимает имена сравниваемых файлов как первые два параметра командной строки).

Но решение об идентичности этих объектов принимается на основании собственного алгоритма сравнения, который игнорирует различия в комментариях, разделителях (пробелы, табуляторы, переводы строки) или регистре символов (за исключением строковых констант).

Формирование скрипта на устранение различий

Скрипт может быть сформирован как слева направо, так и справа налево — обе панели сравнения равноправны для всех алгоритмов.

Скрипт может быть сформирован как для всей загруженной структуры, так и для выбранного в дереве объекта (схема, группа объектов одного типа или один объект).

При формировании скрипта применяются такие же фильтры, как и при загрузке структуры (по типам и по именам). Например, можно сравнить только триггеры и процедуры, т.д. — даже если загрузка происходила без фильтра, так как его можно поменять уже после загрузки структур.

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

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

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

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

Подключение к серверу БД

Для анализа схемы и для применения скрипта возможны два варианта подключения — от имени основной схемы и от имени суперпользователя (sys) Причем второе предпочтительнее, но при отсутствии доступа (пароль sys неизвестен) возможна работа и от имени основной схемы, но некоторая часть метаданных будет в этом случае недоступна. Программа сама пробует оба варианта подключения, вначале пытаясь подключиться от имени sys.

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

Заключение

Описанная технология, возможно, несовершенна — и я буду рад прочитать мнение коллег, даже если буду с ними не согласен.

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

Инструмент постоянно совершенствуется и обрастает новыми возможностями — теперь он умеет делать экспорт и импорт данных с применением фильтра на данные и метаданные, делать полное резервное копирование программы (клиентской части, базы данных и файлов настроек), загружать и скачивать файлы из Oracle Directory, к которой нет прямого доступа через файловую систему, в нем также реализован старый метод хранимых скриптов по версиям — этот метод мы применяем в особых случаях, эти скрипты выполняются перед сравнением по новой технологии.
(я выделил цветом это место после того, как 3 или 4 раза повторил это в комментариях в ответ на вопросы)

Все возможности инструмента доступны через запуск в режиме командной строки, то есть можно создавать пакетные командные файлы, работающие по расписанию без участия человека.

Конечно, такие вещи, как апгрейд структуры БД, особенно при большом количестве отличий, лучше делать вручную, по очереди анализируя каждый отличающийся объект. Кроме того, перед такой операцией настоятельно рекомендуется делать полное резервное копирование БД. Но по мере совершенствования описанных алгоритмов значение квалификации пользователя уменьшается прямо на глазах.

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

Благодарю за внимание.
Поделиться публикацией

Похожие публикации

Комментарии 50

    0
    Спасибо за статью!

    Есть вопросы:
    1. Вы так подробно расписали функционал программы, что невольно возникает вопрос: собираетесь ли вы поделиться ей с сообществом? :)
    2. Ваша программа, фактически, помогает реализовать третий подход из упомянутой вами статьи («подход уподобления структуры БД исходному коду»). И пусть вы не храните в репозитории декларативную структуру БД, вы, тем не менее, генерируете соответствующий XML сами, и все так же используете diff-утилиту (являющуюся темой статьи) для миграции со старой версии на новую.
    Как вы, наверное, помните из статьи, большой проблемой, которую я выделил в этом подходе, являлись изменения в данных. Было бы интересно услышать поподробней, как вы справились с этой проблемой, особенно учитывая, что уже три года используете этот подход.
      0
      1. Поделиться — пожалуйста! Утилита uniVersions входит в состав программного продукта UNA.md (http://una.md) — по вопросам приобретения обращайтесь по контактам, указанным на сайте.

      Я расписал алгоритм так подробно, потому что считаю, что любые идеи не могут принадлежать кому-то одному, а являются достоянием всего человечества. И даже тот, у кого нет прав на программный продукт UNA.md, тем не менее имеет право знать, какие идеи в него заложены.

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

      Мне не нравится аналогия с исходным кодом. Исходный код не имеет такой четкой иерархической структуры, как структура БД, и описанный мной метод к исходному коду абсолютно неприменим.

      Я использую текстовые файлы только для сохранения и восстановления образов объектной структуры — сама же работа по выявлению различий и формированию скрипта происходит в памяти программы с объектной структурой, которая не является текстовым файлом.

      Наверное, я неправильно использовал в тезисах термин «XML-образ». Для меня XML — это иерархическая структура в памяти, но кто-то понимает под этим только файл, то есть текстовое представление этой структуры.

      Так вот, сравниваются не файлы, а объекты в памяти, экземпляры классов объектной модели.

      3. Сравнение хранимых данных — это отдельная тема, описанная программа этим не занимается.

      Дело в том, что взаимосвязи между данными, правила их идентификации и сравнения зависят от конкретного продукта, его бизнес-логики и не формализованы настолько четко, насколько мы это имеем в случае с метаданными Oracle.

      Не думаю, чтобы можно было разработать сколько-нибудь универсальный инструмент для такой задачи.
        0
        1. Отдельно утилита не распространяется?

        2. Есть один нюанс. Моя статья была написана с упором на использование систем контроля версий. Отсюда и аналогия с исходным кодом: в этом подходе декларативные определения меняются со временем, и их изменения можно отслеживать в VCS. В вашем же случае, как я понял, просто есть эталонная структура БД, на которую все БД клиентов мигрируют при помощи вашей утилиты.
        Подход уподобления исходному коду я упомянул потому, что у вашего подхода в потенциале та же проблема: как быть, если перед или после изменения структуры какого-то объекта нужно выполнить трансформации данных?

        3. Конечно же, речь не идет об универсальном решении. Но ведь в статье вы писали о своем подходе, применительно к вашему конкретному продукту, где вы этот подход практикуете уже несколько лет. Поэтому очень интересно было бы узнать ваш опыт. Часто ли возникают такие ситуации, когда автоматически изменить структуру БД недостаточно, и нужно еще и изменять данные? Как вы поступали в таких случаях?
          0
          1. Отдельно — нет, вроде бы… но напишите нашему руководству :-)

          Я распространением не занимаюсь, мое дело — конструирование и кодинг, а остальное мне неинтересно :-)

          2. Мы сравниваем не только с эталоном — нередко приходится сравнивать две версии одной клиентской схемы (например, оригинал — с офисной копией)

          Если перед изменением структуры надо выполнить специфические действия — пишется скрипт (по старой технологии), при апгрейде пронумерованные скрипты выполняются до сравнения.

          3. Такие ситуации возникают нечасто. Во-первых, меняя структуру, мы помним о десятках действующих клиентов. А в тех редких случаях, когда это случается, мы пишем скрипты, я о них уже упоминал несколько раз.

          Фактически uniVersions выросла из программы, применяющей эти пронумерованные скрипты, и эта возможность в ней осталась, хотя и потеряла свою актуальность после разработки алгоритма сравнения с эталоном.
            0
            Спасибо за ответ, ваша ситуация более-менее ясна.
      +1
      >>каждого клиента было собственное видение, какой должна быть его БД
      Т.е. клиенты могли менять структуру БД самостоятельно?

      >>Подключаясь к реальной БД,
      Т.е. вы генерируете скрипт уже на клиенской машине? Тогда получается процесс полуавтоматический и происходит с участием конечного пользователя, если пользователь это — администратор СУБД, то тут понятно, а как быть если у него нет специальных знаний?
        0
        Ну, если все, что ему нужно сделать, — выполнить скрипт, то особых умений здесь не нужно. Но, учитывая, что БД были изначально рассинхронизированны как раз из-за действий клиентов, то похоже, что необходимые навыки и знания у них все же были.
          +1
          Выполнить скрипт? а если при рефакторинге скажем поле стало NOT NULL? тут без человека никак не обойтись. А насчет знаний, тогда этот метод не подходит для массовой программы для среднестатистического пользователя.
            0
            Да, вопрос об изменениях в данных я задал автору в первом комментарии. Ждем ответа :)
              0
              Если поле вдруг стало NOT NULL, то тот, кто его таким сделал, должен был позаботиться о тех клиентах, у кого оно уже содержит пустые значения.

              Тут есть два решения:
              1. Полю задается DEFAULT, и перед применением NOT NULL вначале делается UPDATE всех пустых значений.
              2. Программист сам пишет скрипт на заполнение этих пустых полей, и этот скрипт включается в пронумерованный список скриптов, которые применяется перед сравнением (старая методика)

              Этот метод действительно не подходит для среднестатистического пользователя. Это инструмент для профессионалов — как осциллограф, например.
            0
            1. Да, именно так. Кроме того, что администраторы и штатные программисты клиентов свободно игрались с таблицами, триггерами и пакетами — так этим же занимались и наши внедренцы, которым важно было быстро решить проблему, заткнуть дыру… а там — хоть трава не расти.

            Эти люди не до конца отдавали себе отчет в необходимости поддержания единой структуры БД у всех клиентов, не понимали или не хотели понимать, что любой последующий апгрейд, сделанный другим человеком, не знающим об этих локальных изменениях, просто сведет на нет все усилия предыдущего сотрудника.

            2. Да, скрипт генерируется на клиентской машине. Да, процесс получается полуавтоматический, и может быть даже полностью автоматическим — если вы уверены, что на вашей БД нет локальных изменений в структуре. А если у человека нет специальных знаний — лучше бы ему не делать апгрейд.
            +2
            Есть один большой недостаток, нельзя сравнить больше двух баз за раз.
            Получается очень специфический инструмент.
            Может быть чуть позже я расскажу о стандартизации сотен баз.
              0
              >>стандартизации сотен баз.
              в общем случае это возможно, когда используется инкрементная по версиям миграция. Или тут имеется ввиду другое?
                0
                В какой-то момент у нас было с десяток баз с различающейся структурой. Чтобы синхронизировать их, мы выбрали одну, которая на глаз показалась ближе других к идеалу, и сказали себе: это будет Master Schema. Затем мы сравнивали ее с каждой из остальных БД и, в случае различий структур двух объектов, выбирали: оставить стуктуру объекта из Master Schema, или заменить на структуру из сравниваемой БД.
                После того, как мы таким образом сравнили Master Schema со всеми базами, она приняла конечный вид. После этого для всех БД был сгенерирован diff-скрипт и применен. В итоге все структуры БД синхронизировались.
                Для сравнения структур и для генерации diff'ов мы использовали SQLyog, в котором есть утилита, подобная той, что автор описывает в статье, только для MySQL.

                Стоит отметить, что, в зависимости от количества объектов БД и количества существующих БД, имеет смысл выбирать либо вертикальный, либо горизонтальный подход — или сравнивать всю структуру базы, синхронизируя по 2 БД за раз, или синхронизировать несколько объектов за раз, но всех базах данных.

                Я так понимаю, у вас есть опыт синхронизации структур сотен баз данных? Было бы очень интересно послушать. В нашем случае их был всего десяток, и синхронизация все равно отняло порядочное количество времени.
                  0
                  Я не назвал бы это «большим недостатком».

                  А зачем их сравнивать «за раз»? Чтобы сделать «один универсальный скрипт»? А чем плохо для каждой схемы генерировать на лету персональный скрипт — благо это делается за считанные секунды?

                  У нас есть стандартная схема, ее XML-образ помещается в каждый новый релиз продукта.

                  Но сравнивать приходится и разные копии одной и той же БД. Например, в процессе внедрения продукта у клиента у нас в офисе стоит структурная копия какой-то БД, которая уже установлена и у клиента. Изменения вносятся и там, и тут — а потом надо их синхронизировать, причем в обе стороны.

                  Тут уже нельзя все сделать «одной кнопкой», надо вникать в различия и разбираться, что в какую сторону синхронизировать.
                  +1
                  Предложенный вами подход очень похож на Liquibase, за исключением пользовательского интерфейса и возможности синхронизировать только часть объектов. Очень интересно.
                    0
                    Так для себя же писалось :-)

                    У меня была задача навести порядок в структурах баз, и я придумал и сделал этот инструмент не «для галочки», а чтобы решить проблему
                    +4
                    Для предотвращения проблем с рассинхронизацией схемы БД на разных площадках у нас на проекте используется утилитка oracle-ddl2svn. Автоматическое отслеживание изменений схемы БД Oracle в системе контроля версий SVN. Схема БД храниться в виде DDL скриптов.

                    Плюс программы, что она делает все автоматически. Т.е. настраивается периодическое задание и потом остается только смотреть, что поменялось в схеме за указанный период.

                    Утилиту написал я в начале года. Вначале искал что-нибудь уже готовое, но ничего не нашел. Решил потратить пару выходных и написать свое. В итоге потратил больше, но написал довольно универсальную программку. Выложил ее на гуглокод, опубликовал ссылку на sql.ru и stackoverflow.com. Народ ей пользуется и даже присоединился коммитер из США )
                      +1
                      >>Плюс программы, что она делает все автоматически
                      а как она автоматически разруливает такие неопределенности типа изменения поля c NULL на NOT NULL???
                        +1
                        >>а как она автоматически разруливает такие неопределенности типа изменения поля c NULL на NOT NULL???

                        Автоматически oracle-ddl2svn ничего не разруливает. Только сообщает, что есть изменения.
                        Diff'а для генерации скрипта по изменениям DDL в программе нет.
                        Кстати, такой diff есть в PL/SQL developer и в TОAD.

                        А так DDL поменяется, например, было
                        CREATE TABLE "CTC"."TABLE1" 
                           (	"ID" VARCHAR2(16));
                        

                        Стало
                        CREATE TABLE "CTC"."TABLE1" 
                           (	"ID" VARCHAR2(16) NOT NULL ENABLE);
                        

                        Это зафиксируется в SVN
                          0
                          т.е. окончательный скрипт миграции пишется все равно руками?
                            0
                            да
                        0
                        «Плюс программы, что она делает все автоматически»
                        Как выяснилось, делает она у вас далеко не «все» :-)
                          +1
                          «Все» — неточный термин =)
                          У меня цель была не допустить рассинхронизацию. Достигается с помощью oracle-ddl2svn.
                          А тут топик про то, как сводить разные версии к одной.

                          Профилактика обычно дешевле лечения.
                            +1
                            Профилактика — это не дать вносить изменения в обход стандартного протокола.

                            А когда изменения уже есть — пусть их показывает ваша или моя программа — это уже наступила фаза для «лечения».

                            У нас нет системы контроля версий, а разработка часто ведется прямо на сервере клиента, и обновленные триггера и пакеты часто там и остаются (а потом теряются при апгрейде и восстанавливаются после криков «Караул!» методом сравнения с образом вчерашней структуры).

                            Работают у нас вчерашние (а часто и сегодняшние) студенты, у которых высшая оценка своему труду — «Все работает». А как именно оно работает, и как это отразится на других — им невдомек. Текучка кадров — объективная реальность.

                            Поэтому фактически все апгрейды выполняют специально обученные люди как раз в полуавтоматическом режиме, сливая отличающиеся объекты по одному. Shift+Click :-)
                              +1
                              Так может быть, вам стоило бы задуматься о центральном репозитории кода, в который бы и сабмиттились изменения БД? А еще, говорят, ревью кода — хорошая практика :)
                                0
                                Кто-то из нас кого-то не понимает. Попробуйте говорить по-русски :-)

                                Есть у нас «Центральный репозиторий» — это стандартная схема, куда никому нет доступа, кроме меня и еще пары человек. Но изменения в базах делаются у клиентов как решение мелких задач, а я потом заливаю отличия в стандартную схему в офисе, откуда потом они попадают ко всем остальным.

                                «Ревью кода» — рефакторинг — я делаю регулярно, когда сливаю отличия в пакетах. Если нужно залить только часть текста, то там моя программа бессильна — точнее, она только показывает отличия, а я открываю пакет в Toad или PL/SQL Developer, вручную переношу туда изменения и снова сравниваю измененный пакет в uniVersions
                                  +1
                                  Да, вы действительно меня не так поняли. Под центральным репозиторем кода я имел в виду именно систему контроля версий. Это полезно для, как ни странно, контроля версий :) и хранения их истории. Вы видите все изменения, кто и когда их внес.

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

                                  Впрочем, хозяин — барин. Это был всего лишь совет из личного опыта.

                                  P.S. Ревью кода (code review) — это совсем не рефакторинг. Во всех командах, где я его встречал, code review производился ДО сабмита в репозиторий.
                                    0
                                    У нас пытались внедрить CVS, но не пошло (только мешало). В другой фирме, где я подрабатывал, все с ним работают, но мне оно не показалось удобным. Наверное, все дело в общей культуре всех участников процесса :-)

                                    У нас фактически это и происходит, я сам и есть CVS. Я сам заливаю изменения в стандартную схему, и сам раздаю новые релизы с обновленными образами структуры БД.

                                    P.S. Спасибо за разъяснение. Указание момента, когда именно выполняется code review, сразу объясняет, что оно такое :-)
                                      0
                                      ru.wikipedia.org/wiki/Code_review
                                      Правда, там не очень чётко сказано, что это когда код одного программиста обязательно просматривается другим программистом, как правило каждый смотрит чей-то код.
                                      0
                                      А если без шуток, то у меня такое ощущение, что это вы меня не поняли. И ваши пояснения только укрепляют меня в этом ощущении.

                                      >> Так может быть, вам стоило бы задуматься о центральном репозитории кода, в который бы и сабмиттились изменения БД?

                                      Вообще, ваш насмешливый тон здесь неуместен. Естественно, что над этой проблемой работали несколько неглупых людей в нашей фирме, и поверьте мне, что они задумывались о многих вещах, говорить о которых не хватит места в этой статье.

                                      Наша стандартная схема — как раз и есть то, о чем вы говорите, называя ее Центральным репозиторием, и она выполняет как раз те же самые функции.

                                      То, что вы называете словом «сабмититься», происходит, когда я, по просьбе кого-то из разработчиков, заливаю новые изменения в стандартную схему — используя все тот же uniVersions.

                                      >> А еще, говорят, ревью кода — хорошая практика :)

                                      И снова ваш насмешливый тон неуместен. Разумеется, при обнаружении отличий в телах триггеров или пакетов я вначале вникаю в суть этих отличий, и только потом вношу изменения (то есть анализ происходит именно до сабмита).

                                      Практика — критерий истины. Наша программа реально работает.
                                        0
                                        Вы слишком резко реагируете. Впрочем, простите, я не хотел вас задеть. Просто помните, что на каждом интернет-ресурсе — свой стиль общения и свои нормы.

                                        Я написал про центральный репозиторий и ревью кода потому, что у вас разработка ведется прямо на серверах клиентов.
                                        У вас уже есть «генеральная» версия схемы — отлично. Вы проверяете все изменения перед применением на этой схеме — прекрасно. Но в таком случае, вам стоило бы сделать этот процесс обязательным перед редактированием объектов БД на серверах клиентов. Ведь всегда можно создать тестовую БД, протестировать изменения на ней, а уже затем отдать вам в центральную схему, после чего последует синхронизация изменений на все БД клиентов.
                                        Это бы решило проблемы, о которых вы сами же и упомянули.

                                        Впрочем, я вам ничего не навязываю. Пожалуйста, воспримите это как совет. Если он вам не подходит — он вам не подходит.
                                          0
                                          Мы именно так и стараемся делать.

                                          Точнее, когда это делаю я, а не студенты.
                                            0
                                            Извините за резкость, я старался быть настолько толерантным, насколько мог :-)

                                            >> на каждом интернет-ресурсе — свой стиль общения и свои нормы

                                            Смею предположить, что не стиль меняет людей, а наоборот.

                                            «Не стоит прогибаться под изменчивый мир» :-)

                                            Еще раз извините, если я был неправ
                            0
                            У нас SQL Server и мы сталкивались с подобными проблемами. Для их решения мы пользовались готовыми продуктами от Redgate, возможно они подойдут и вам.
                            Сейчай schema compare для SQL Server встроена в VisualStudio 2010.
                              +2
                              Для Oracle есть Toad, который умеет делать оочень много полезных вещей по работе со схемами. В свое время мы делали полный экспорт схем двух баз в скрипты, а затем сравнивали обычным diff-ом. Хотя у Toad-а для этого есть специальная тулза.
                                +1
                                Если бы тоад не был таким глючным (да-да-да) и дорогим, он был бы самым лучшим-лучшим. Ну а так он просто лучший.
                                  0
                                  Я давно пользуюсь и Toad, и PL/SQL Developer — но той функциональности, что мне нужна, там и близко нет
                                    0
                                    Toad вроде бы написан на Delphi с применением Developer Express, так что часть глюков можно списать на эти две составляющие :-)

                                    Мне тоже он очень нравится — для целей администрирования он «лучший».

                                    Но для работы с PL/SQL лучше и удобнее PL/SQL Developer — писать пакеты я предпочитаю в нем.

                                    Я уже говорил, что у меня сравниваются не файлы, а объекты в памяти программы, написанной на С++

                                    Только так я могу сам управлять процессами идентификации и сравнения объектов метаданных.

                                    (под идентификацией я понимаю алгоритм обнаружения аналогичного объекта в другой структуре — точнее, принятия решения, это он же или не он)
                                      0
                                      А у Вас там хитрый алгоритм? А можно поподробнее?
                                        0
                                        Да не особенно «хитрый» — можно и поподробнее.

                                        Вначале процитирую абзац из самой статьи:

                                        В основе идентификации сравниваемых узлов лежат два критерия — общий родительский узел и одинаковое имя самого узла. Имя узла используется и для сортировки дочерних узлов одного родительского узла. Поэтому именованию узлов разных типов объектов придается особое значение.

                                        Отсюда есть следствия:
                                        — у каждого узла есть текстовое имя (регистронезависимое)
                                        — среди дочерних узлов одного родительского узла все имена уникальны

                                        При формировании имени объекта важно ухватить его суть. Например, для таблиц или пакетов это просто имя самого объекта. Переименован — значит, уже «не он». Отсюда тоже есть следствия: нельзя просто так переименовывать объекты во избежания их дублирования. Например, мне jlyf;ls не понравилось имя триггера INSTEAD OF на какой-то VIEW, и я его переименовал. И через какое-то время на схемах стала гулять эта VIEW с обоими триггерами, дклающими одно и то же (естественно, это ошибка).

                                        Есть объекты, для которых их имя в БД неактуально с точки зрения идентификации. Это характерно для уникальных объектов или объектов, не допускающих дублирования. Например, первичный ключ, как бы он ни назывался, должен сравниваться только с другим первичным ключом той же таблицы. Поэтому имя соответствующего узла строится как имя его типа: «Primary key». Имена уникальных констрейнтов строятся как имя типа «Unique» плюс список полей, по которым построен этот констрейнт. Так же и для индексов, и так далее.
                                    0
                                    Занимаюсь такой фигнёй тоже.

                                    Реализовано так. Подходит разработчик, говорит: «Надо мне бы вот такое сделать». Разработчиков к DDL не пускаем. Я делаю, сохраняю скрипт изменений под номером его задачи в trac. Разработчик выставляет дополнительное поле в trac в «Проводилась модификация БД». После integrated и его заливкой на ветку, я выбираю по вышеуказанному признаку в trac его номер тикета и просто выполняю скрипт на тестерской, девелоперской, других базах.

                                    Казалось бы слабое место, это модификация пакетов, где каждый девелопер может попросить поменять свою часть, но это уже ручками. Часть пакета не поменять =)

                                    Спасибо за статью и, особенно, за комментарии, щаз пойду копать новые знания.
                                      0
                                      Здесь ключевая фраза — «Разработчиков к DDL не пускаем» :-) У нас уже пустили, и обратного хода нет.

                                      Да, пакеты не имеют такой четкой иерархической структуры, поэтому у нас есть ответственные за модули, и изменения в закрепленных за ними пакетах проходят через них… а остальное — через меня :-)
                                      0
                                      Complete Compare в ErWin ведь как раз это и делает, сравнивает структуру в ErWine и в базе, достаточно не отлынивать от рисования таблиц перед вставкой их в БД.
                                        0
                                        Отправил раньше времени:
                                        генерирует скрипт для изменений/вставки/удаления и прямо из интерфейса ErWin можно запустить экспорт.
                                        Но вот на другие удаленные точки этот скрипт приходится расскидывать вручную.
                                          0
                                          Люди! У меня сравниваются не только таблицы :-) а и такие вещи, как synonym, public synonym, public grant, policy, context, role, privilege…

                                          Универсальные инструменты убоги как раз в силу своей универсальности. Наш инструмент заточен под Oracle, причем только на 10g и выше — мы не решали задачу универсальности, а делали вещь «для внутреннего употребления» :-)

                                          Зато можно «отлынивать» и ничего не рисовать — я могу сравнивать даже схемы, которые делали другие люди.
                                            0
                                            ErWin сравнивает и синонимы и гранты и т.д.
                                            Триггеры, процедуры и пакеты только в ErWin не ведем.

                                            Рисовать полезно, когда будет 5000 с лишним таблиц, это будет серьезная помощь.
                                              0
                                              контексты ErWin сравнивает? секвенсоры, типы, привилегии схем и ролей?

                                              и потом, я уже говорил — мне для сравнения схем не нужно ничего, кроме самих схем, и это очень удобно.
                                          0
                                          Для Firebird/Interbase есть похожий инструмент в IBExpert. Часто им пользуюсь.
                                            0
                                            Большинство инструментов только показывают отличия, не решаясь что-то менять.

                                            uniVersions позволяет синхронизировать объект «одной кнопкой» (фактически — Shift+Click)
                                            Эта комбинированная операция делает три действия:
                                            — генерирует скрипт на разницу
                                            — выполняет скрипт на сервере
                                            — обновляет описание объекта

                                            Как результат — синий или красно-белый значок на дереве становится чисто белым, а пользователь переходит к другому «цветному» значку.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое