13

私はこのブログを読んでいて、書かれている 5 つの投稿について質問があります。私が理解していることから、すべての SQL DDL ステートメントを含む大きなベースライン スクリプトを作成します。これが完了したら、個別のスクリプトで各変更を追跡します。

しかし、スクリプト ファイルの名前がアプリケーションの特定のビルドにどのように関連付けられるかがわかりません。彼は、ユーザーが 3.1.5.6723 のバグを報告した場合、スクリプトをそのバージョンで再実行できると述べています。そして、彼が言うように、テーブルなどへの変更を独自のファイルで追跡しますか、それともすべての DLL の変更を同じスクリプト ファイルに格納してから、ビューなどを独自のファイルに格納しますか?

4

5 に答える 5

15

まず第一に、DB のアップグレードは悪ですが、そのブログでは完全な悪夢について説明しています。

アップグレード アプローチに基づいてプログラマー コンピテンシー マトリックスを作成できます。

  • レベル 0: アップグレードは一切ありません。顧客はおびえ、アプリケーションによって提供される UI またはサードパーティの DB 管理ソリューションを使用してデータを手動で移動します (信じてください、それは実際に可能です)。
  • レベル 1: DB ダンプをアップグレードするスクリプトがあります。顧客は安全だと感じていますが、今後 1 ~ 2 年間は些細で非常に苛立たしい問題を解決してくれます。システムは機能していますが、変更は許可されていません。
  • レベル 2: テーブルの変更。特にアップグレード中に問題が発生した場合は、途方もないダウンタイムが発生します。大きな問題があり、100% 安全な結果が得られる保証は事実上ありません。データ変換は、バグのあるスクリプトによって管理されます。顧客は満足していません。
  • レベル 3: スキーマのない設計: バグのあるスクリプトが DB の構成を変換できるようにするための 1 ~ 2 時間のダウンタイム (多くの場合、このステップは DB を損傷する可能性があります)。サポート担当者は、すべてのコーヒー備蓄を完全に使い果たしました。
  • レベル 4: レイジーで透過的なアップグレード: ダウンタイムはありませんが、いくつかの問題が発生する可能性があります。顧客はほぼ満足していますが、以前の経験を覚えています。
  • レベル 5: 理想的なアーキテクチャであり、明示的なアップグレードは必要ありません。完全な幸福。顧客は、アップグレード手順が何であるかを知りません。開発者は生産的で落ち着いています。

すべての技術的な問題について説明しますが、その前に次のことを述べさせてください (かなり長い回答をお許しください)。

  • 現在、開発サイクルは非常に圧縮されており、DB は巨大です
  • ほぼすべての機能がスキームの変更を導入し、互換性を損なう可能性があるため、シンプルで安定したアップグレード手順を用意するか、機能を延期する可能性があります
  • 問題が顧客によって特定される可能性があるため、いくつかのアップグレード手順が必要な緊急のホットフィックス ビルドが必要になる可能性があります。
  • 一般的に言えば、あなたとあなたの顧客との間の障壁を避ける方がはるかに良いです

レベル 0 とレベル 1 どちらの場合も明白でばかげています。誰でもそれを避けるべきです。

レベル 2 変更は小さなテーブルではそれほど悪くありませんが、大きなテーブルでは問題になる可能性があります。非常に大きなテーブル (>1Gb) では、ALTER TABLE が完了するまでに数時間または数日かかる場合があります。さらに、スキーマのアップグレードの問題のみが解決されますが、保存されたデータはどうなりますか? また、このアプローチの背後にある実際の障害を理解するために、物理的なデータ レイアウトについて検討することをお勧めします。手順全体が安全ではない可能性があるため、バックアップがあることを確認してください。

ソリューション:

レベル 3 スキーマのアップグレードの問題は、スキーマを上位層に移動することで解決されます。スキーマレス ソリューションは、主にリレーショナル モデルの背後にあるすべての機能を無効にするため、多少制限があります。高速アップグレードとリレーショナル代数を使用する機能の両方を備えたハイブリッド アプローチを提案できます。いくつかの興味深い記事があります:

アップグレード手順の複雑さは依然として存在し、アプリケーション レベルに移動しただけであることに注意してください。関連するシナリオは多数ありますが、ここでは、私が数年間使用してきた 1 つのハイブリッド システムについて説明します。データモデルを「関係を持つエンティティ」と表現できます。エンティティ間の関係は DB レベルで表現され、エンティティ自体は XML BLOB として格納されていました。

このシステムは成熟しており、十分な数の顧客を抱えていました。多くの機能リクエストがあったため、R&D チームと QA チームは少しストレスを感じていました。最初のアップグレード手順は、DB から XML BLOB を読み取り、DOM API を使用してアップグレードし、DB に書き戻すスタンドアロンの Java アプリケーションとして実装されていました。実際のアプローチは非常に簡単に見えますが、背後にはいくつかの隠れた問題があります。

  • アップグレード ロジックには多少のバグがある可能性があるため、間違った XML データを書き込む可能性があり、顧客のダウンタイムが大幅に増加します。
  • 1 ~ 2 GB の XML の読み取り、変換、書き込みには時間がかかる場合があります。
  • アップグレード手順のすべてのステップは、自動化されたテストでカバーする必要があります (CI は必須です)。
  • 隠れた不具合は 1 日か 2 日で見つかる可能性があるため、新しいデータが挿入されるため、バックアップは役に立ちません。
  • ビルド間のアップグレードが必要な場合は特に、アップグレード コードが少し面倒になる可能性があります (アジャイル チームの通常の要件)。

より厳密なアップグレード手順の定義、検証ルール、および実際のデータ (すべての顧客から収集された) に対して CI システムによって実行される広範なテストを使用して、すべての潜在的なリスクを軽減しようとしました。古いアップグレード スクリプトによってずっと前に導入された古い問題が原因で、いくつかの手順が失敗するのを見て驚きました。その隠れた問題を修正するために、個別のアップグレード手順が開発されました。アップグレード時間を合理的な 20 ~ 30 分に短縮するために、いくつかの最適化も実行されました。コンソールベースのプログレスバーの実装が残りを行いました。

簡単な注意: エンドユーザーは、実行時間の長い (> 2 分) 操作の進行状況を確認したいと考えています。そんな「楽しみ」を忘れずに実装してください。

当初、DB バージョンは別のテーブルに格納されていました。このアプローチは使用しないでください。エンティティを個別にバージョン管理し、アップグレード中に DB 全体がロックされるのを回避する方がはるかに優れています。

例として 1 つのアップグレード手順を示します (すべての検証および検証手順は処理ロジックの背後<build/>に隠されています)。<version/>「-」は少ないことを意味し、「*」は任意のビルドを意味します

<?xml version="1.0"?>
<upgrade>

   <version name="-7.4">
      <build name="*">
        <script class="upgrade.version7.Replace...Script"/>
        <script class="upgrade.version7.Update...Script"/>
         <!-- 5 scripts skipped -->
      </build>
   </version> 
   <version name="-7.6">
      <build name="*">
    <script class="core.DatabaseUpdateVersion" version="7.6.48"/>
      </build>
   </version>
   <version name="7.6">
      <build name="*">
        <script class="upgrade.version7.Update...Script"/>
    <script class="core.DatabaseUpdateVersion" version="8.0.40"/>
         <!-- 7 scripts skipped -->
      </build>
   </version>

   <version name="8.0">
      <build name="-53">... </build>
      <build name="+52">... </build>
   </version>

   <version name="8.1">
      <build name="-8"> ... </build>      
     <build name="-9">...</build>      
     <build name="-26">...</build>      
     <build name="-40">...</build>      
      <build name="-45">...</build>      
      <build name="-56">...</build>      
      <build name="-61">...</build>      
      <build name="-63">...</build>      
      <build name="-64">...</build>      
      <build name="-68">...</build>      
      <build name="-69">...</build>      
      <build name="-77">...</build>      
      <build name="-79">...</build>      
      <build name="-80">...</build>      
      <build name="-86">...</build>      
      <build name="-88">...</build>
      <build name="-89"> ... </build>
   </version> 

   <version name="8.2">...</version>
</upgrade>

各スクリプトは小さな Java または Groovy の実装です (XSLT も使用されました)。その後、ダウングレード手順も開発されましたが、これはまったく別の話です。

アプリケーション層のレベル 4 データ スキームにより、非常に多くの興味深いことが可能になります。たとえば、XML をprotobufに置き換えることができます。いつものように、これを行うにはいくつかの理由があります (より簡単である、より高速であるなど)。ビルダーの概念が気に入らない場合は、代わりに倹約を使用できます。

とにかく、protobuf を使用すると、(格納されたデータに関して) 下位互換性のあるシステムをほとんど問題なく作成できます。ところで、良い利点。システムに下位互換性があるため、遅延型で完全に透過的なアップグレードを簡単に実装できます。これは、バックグラウンド プロセスまたはリクエストに応じたアップグレードなどの場合があります。幸いなことに、ダウンタイムがなく、ユーザーは満足しており、アップグレードをより頻繁に行うことができます。つまり、迅速に開発し、顧客の要求に迅速に対応し、より多くの成功を収めることができます。

レベル 5 申し訳ありませんが、今回はありません。アップグレード戦略には注意してください。いくつかのスキーマが定義されたシステムを販売し、自分自身をロックアウトするのは非常に簡単です。新機能なし -- 顧客なし。

シンプルだが非常に便利なチェックリスト:

  • お客様から寄せられた問題を迅速に解決できますか?
  • お客様がシステムをアップグレードしても安全ですか (少なくともミッション クリティカルな場合)?
  • 問題を特定するのにどれくらいの時間が必要ですか?
  • 自動検証はありますか?

読んでくれてありがとう。

于 2012-10-10T20:09:43.397 に答える
4

私は、個人的にはliquibaseを使用しています。非常に便利なツールです。オラクルと複雑なバージョン管理スキームを使用して、チュートリアルなどの非常に複雑なワークフローを許可します

于 2012-10-08T20:16:13.693 に答える
2

テーブルとビューへの変更は、独自のファイルには保持されません。変更を行うたびに、新しい変更スクリプトを作成します。したがって、テーブル 'X' を 5 回変更すると、これらの変更ごとに 5 つの異なる変更スクリプトが作成されます。

特定のリリース バージョンのスキーマを作成する場合は、そのリリース用にラベル付けされたソース コードを取得します。ベースラインからデータベースを作成します。次に、そのバージョンのコードで変更スクリプトを時系列で実行します。例えば

db_scripts/

2012-01-01 baseline.sql:
create table book (
   book_name varchar(100),
   author_name varchar(100)
)
--- label version_1.0

2012-02-01 add_publisher.sql:
alter table book add column publisher varchar(100)
--- label version_1.1

2012-03-01 add_publish_date.sql:
alter table book add column publish_date datetime
--- label version_1.2

2012-04-01 add_rating.sql:
alter table book add column rating integer
--- label version 1.3

ここで、バージョン 1.2 のデータベースを再作成するとします。

  1. コードをラベル version_1.2 に同期します。
  2. スクリプトをbaseline.sql、add_publisher.sql、add_publish_date.sqlの順に実行します
于 2012-10-06T09:49:28.980 に答える
2

Liquibase の代わりに、独自のアップグレード/ダウングレード SQL スクリプトを作成できるFlyway ( http://flywaydb.org/ ) を使用できます。これにより、柔軟性が向上し、ビューやストアド プロシージャにも機能します。

Liquibase では、独自の XML ベースの言語を使用してスキーマを変更する必要がありますが、これは多少制限される可能性があります。

于 2012-10-10T13:55:51.100 に答える
0

データベースにバージョン番号を保持し、起動時に更新スクリプトを適用することは、この戦略の重要な部分です。

スタートアップの仕組みは次のとおりです。

  • データベースの DB_VERSION レコードをチェックし、
  • アップデート > 現在のバージョンを検索します。たぶんコードで。
  • 該当する各「更新」、スクリプト、またはプログラム アクションを実行します。
  • DB_VERSION は毎回更新されるため、途中で失敗しても再実行できます。

例:

  • 現在DB_VERSIONを見つける= 789;
  • 洗練されたコード、または大きくて長い IF チェーンは、790 以上の更新を検出します。
  • #790 を更新し、顧客とアカウントのテーブルをアップグレードします。
  • 更新 #791、E メール テーブルのアップグレード。
  • #792 を更新し、Order テーブルを再構築します。
  • 現在のデータベース バージョン = 792。

いくつかの注意事項があります。これはかなりうまく機能します。人々は 100% 信頼できるはずだと主張しますが、そうではありません。

不完全なスクリプトの問題、フィールドの長さの違い、またはサーバーのバージョンの違いにより、スクリプト/SQL が一部のデータベースではパスしても、他のデータベースでは失敗することがあります。

実行するスクリプトを見つけることは、多くの IF ステートメントを含む大きな単一のメソッドと同じくらい簡単です。または、よりエレガントに、検出またはメタデータを介してスクリプトをロードすることもできます。SQL だけでなく、プログラム コードを含めることができると便利な場合があります。

public void runDatabaseUpgrades() {
    if (version < 790) {
      // upgrade Customer and Account tbls
      version = 790;
    }
    if (version < 791) {
      // upgrade Email tbl
      version = 791;
    }
}
于 2012-10-06T10:20:59.187 に答える