1

主キーとして 1 つの列 GUID (アルゴリズムのようなカスタム GUID) を持つマスター テーブルと、この GUID 列と外部キー関係を持つ 8 つの子テーブルを持つかなり巨大なデータベースがあります。すべてのテーブルには、約 300 万から 800 万のレコードがあります。これらのテーブルには、BLOB/CLOB/TEXT や、通常の数値、varchar、日付、およびタイムスタンプ (各テーブルに約 15 ~ 45 列) だけのその他の派手なデータ型はありません。主キーと外部キー以外のパーティションやその他のインデックスはありません。

現在、カスタム GUID アルゴリズムが変更されており、競合はありませんが、古いデータをすべて移行して、新しいアルゴリズムを使用して生成された GUID を使用したいと考えています。他の列を変更する必要はありません。最優先事項はデータの整合性であり、パフォーマンスは二の次です。

私が考えることができた可能な解決策のいくつかは次のとおりです(おそらく、それらはすべて1つのアイデアのみを中心に展開していることに気付くでしょう)

  1. 新しい列 ngu_id を追加し、新しい gu_id を入力します。制約を無効にします。ngu_id を gu_id として子テーブルを更新します。rename ngu_id->gu_id; 拘束を再度有効にする
  2. 子テーブルから 1 つのマスター レコードとそれに依存する子レコードを読み取ります。新しい gu_id で同じテーブルに挿入します。古い gu_ids を持つすべてのレコードを削除します
  3. 制約を削除します。すべての子テーブルが更新されるように、マスター テーブルにトリガーを追加します。古い gu_id を新しい新しい gu_id で更新し始めます。拘束を再度有効にする
  4. すべての子テーブルが更新されるように、マスター テーブルにトリガーを追加します。古い gu_id を新しい新しい gu_id で更新し始める
  5. すべてのマスター テーブルと子テーブルに新しい列 ngu_ids を作成します。ngu_id 列に外部キー制約を作成します。更新トリガーをマスター テーブルに追加して、値を子テーブルにカスケードします。新しい gu_id 値を ngu_id 列に挿入します。gu_id に基づく古い外部キー制約を削除します。gu_id 列を削除し、ngu_id を gu_id に名前変更します。必要に応じて制約を再作成します。
  6. 利用on update cascade可能な場合は使用しますか?

私の質問は次のとおりです。

  1. より良い方法はありますか?(頭を砂に埋められない、やらなきゃ)
  2. これを行う最も適切な方法は何ですか? (Oracle、SQL サーバー、および mysql4 でこれを行う必要があるため、ベンダー固有のハックは大歓迎です)
  3. このような演習の典型的な失敗点と、それらを最小限に抑える方法は何ですか?

あなたがこれまで私と一緒にいたら、ありがとう、そしてあなたが助けてくれることを願っています:)

4

4 に答える 4

3

あなたのアイデアはうまくいくはずです。最初はおそらく私が使用する方法です。これを行う際の注意事項と考慮事項:
最新のバックアップがない場合は、これを行わないでください。
両方の値をメイン テーブルに残します。そうすれば、古い書類からアクセスする必要があるレコードを特定する必要がある場合でも、それを行うことができます。これを行う間、メンテナンスのためにデータベースを停止し、シングル ユーザー モードにします。このようなことをしているときに必要な最後のことは、途中でユーザーが変更を加えようとすることです。もちろん、シングルユーザーモードになったら最初のアクションは前述のバックアップです。おそらく、使用量が最も少ない時間にダウンタイムをスケジュールする必要があります。まずはdevでテスト!これにより、生産を終了する必要がある期間についてのアイデアも得られるはずです。また、いくつかの方法を試して、どれが最速かを確認することもできます。
メンテナンスのために予定された時間にデータベースがダウンすること、およびデータベースが再び利用可能になると期待できる時期であることを、事前にユーザーに伝えてください。タイミングが良いことを確認してください。四半期ごとのレポートを実行するために遅くまで滞在する予定があり、データベースが利用できず、それを知らなかった場合、人々は本当に腹を立てます。
かなりの数のレコードがあるため、子テーブルの更新をバッチで実行することをお勧めします (カスケード更新を使用しない理由の 1 つ)。これは、1 回の更新で 500 万件のレコードを更新しようとするよりも高速です。ただし、一度に 1 つのレコードを更新しようとしないでください。そうしないと、来年もこのタスクを実行し続けることになります。
すべてのテーブルの GUID フィールドのインデックスを削除し、完了後に再作成します。これにより、変更のパフォーマンスが向上するはずです。

于 2008-11-20T19:13:01.367 に答える
0

ソリューションで探しているものを説明していないため、「最適な」または「最適な」アプローチが何であるかを言うのは困難です。たとえば、新しい ID に移行している間、テーブルをクエリで使用できるようにする必要がありますか? 同時に変更できるようにする必要がありますか? できるだけ早く移行を完了することが重要ですか? 移行に使用するスペースを最小限に抑えることは重要ですか?

そうは言っても、すべてが要件を満たしていると仮定して、他のアイデアよりも 1 を優先します。

子テーブルを更新するためのトリガーを含むものはすべて、エラーが発生しやすく、複雑すぎるため、#1 ほどうまく機能しない可能性があります。

新しい ID が古い ID と衝突することはないと想定しても安全ですか? そうでない場合、ID を 1 つずつ更新することに基づくソリューションでは、衝突を心配する必要があります。これは、急いで面倒になります。

CREATE TABLE AS SELECT(CTAS) を使用して新しい ID を新しいテーブルに入力することを検討しましたか? 既存のテーブルのコピーを作成するため、追加のスペースが必要になりますが、既存のテーブルを適切に更新するよりも高速になる可能性があります。アイデアは次のとおりです。(i) CTAS を使用して古いテーブルの代わりに新しい ID を持つ新しいテーブルを作成する、(ii) 新しいテーブルに適切なインデックスと制約を作成する、(iii) 古いテーブルを削除する、(iv) 新しいテーブルの名前を変更するテーブルを古い名前に変更します。

于 2008-11-22T00:14:52.833 に答える
0

実際、それは RDBMS に依存します。

Oracle を使用する場合、最も簡単な選択は、すべての外部キー制約を「延期」 (コミット時にチェック) し、単一のトランザクションで更新を実行してからコミットすることです。

于 2008-11-22T01:04:06.557 に答える
0

古い pk 値と新しい pk 値を含む新しいテーブルを作成します。これまでに何も壊れていないことを確認するために、両方の列に一意の制約を配置します。

制約を無効にします。

すべてのテーブルに対して更新を実行して、古い値を新しい値に変更します。

PK を有効にしてから、FK を有効にします。

于 2008-11-20T20:03:29.157 に答える