7

警告: この悲惨な話には、コードの臭い、設計上の決定の誤り、および技術的負債の例が含まれています。

SOLID の原則に精通している場合は、TDD を実践し、作業の単体テストを行ってください。誰かの不幸を笑い飛ばしたり、自分の後継者のためにそのような途方もないがらくたの山を決して残したりしないことを知って、自分自身の素晴らしさにうめき声を上げたりしたくない場合を除きます。

それで、あなたが快適に座っているなら、私は始めます。

私が継承し、過去 7 か月間サポートとバグ修正を行ってきたこのアプリでは、6 か月半前に去った開発者によって、私はボールアップの DOOZY を残されました。はい、始めて2週間。

ともかく。このアプリにはclientsemployeesvisitsテーブルがあります。

と呼ばれる (または同様のもの) というテーブルもありますAppNewRef... それを待つ... 他の各テーブルに使用する次のレコード ID が含まれています。したがって、次のようなデータが含まれる場合があります:-

TypeID    Description     NextRef
   1      Employees       804
   2      Clients         1708
   3      Visits          56783

アプリケーションが の新しい行を作成するとき、テーブルをEmployees調べてAppNewRef値を取得し、その値を ID に使用して、NextRef列を更新します。Clients、および使用Visitsする他のすべてのテーブルについても同じことNextIDがここに格納されます。

はい、わかってIDENTITYいます。このデータベースには列の自動番号付けはありません。いずれも「Accessアプリだった頃」という言い訳で。これらの ID は (VB6) コードで long として保持されます。したがって、最大 21 億 4,700 万レコードが可能です。OK、それはかなりうまくいっているようです。(データベースではなく、アプリが更新し、ロック/更新などを処理しているという事実は別として)

そのため、ユーザーは非常に満足して 、 などを作成EmployeesClientsていますVisitsVisits IDは、一度に数十個ずつ着実に増加しています。その後、問題が発生します。サーバーが正常に動作しなくなり、アプリが応答しなくなるため、訪問のバッチを作成しているときにクライアントがデータベースの破損を引き起こしています。そのため、彼らは辛抱強く待つのではなく、タスク マネージャーを使用してアプリを強制終了します。確かに、アプリはロックされているようです。

今年の初めにロールバックすると、開発者のティム (本名。ここでは有罪を保護するものではありません) は、UI が「レスポンシブ」のままになるように、段階的にバッチ更新を行うようにコードを変更し始めました。それからエイプリルがやって来て、彼は通知を処理しており(今のシーンを想像できますよね?)、彼は更新を完了するためにビーブリングしています。

4 月末と 5 月初めに、一部のクライアントを更新します。今後数か月にわたって、それらの多くを更新します。

ティム (本名、覚えておいてください) と私 (ティムが去る 2 週間前に開始した)、および 1 週間後に開始した他の新しい開発者には見えませんが、訪問テーブルの ID は大きく飛躍し始めます。巨大とは、一度に 10000、20000、30000 を意味します。場合によっては数十万。

これは、使用される ID の急速な増加を示すグラフです。

彼のグラフを見てください

11 月にロールします。顧客がテクニカル サポートに電話し、エラーが発生したと報告しました。エラー メッセージを見て、コードをデバッグできるようにデータベースを要求します。長い間、値が大きすぎることがわかりました。いくつかのクエリを実行し、情報を取得して Excel にドロップし、グラフ化します。

このアプリはその ID を他の DLL や OCX に渡し、それらのインターフェイスを壊すことは、私がやっている傷の全世界のように思えます。今は出会いたくない。

私が調査している潜在的なアイデアの 1 つは、ID を変更して、ID をより低いレベルに下げることができるようにすることです。基本的にギャップを埋めます。ROW_NUMBER機能の使用

私が考えているのは、これらの訪問IDへの外部キー参照を持つ各テーブルに新しい列を追加することです(適切な外部キーの心ではなく、これらの制約はこのデータベースには存在しません)。この新しい列には、訪問 ID の古い (現在の) 値を格納できます (混乱させるために、一部のテーブルでは と呼ばれEventID、一部のテーブルでは と呼ばれていVisitIDます)。

次に、その を参照する他の各テーブルについてVisitID、新しい値に更新します。

アイデア?提案?T-SQL のスニペットは、感謝して受け取ったすべての人を支援します。

4

2 に答える 2

2

オプション 1:

すべての外部キー関係を明示的に制約し、それらを に設定しますON UPDATE CASCADE

これは、ID を変更するたびに、外部キーが自動的に更新されることを意味します。

次に、このようなものを実行するだけです...

WITH
  resequenced AS
(
  SELECT
    ROW_NUMBER() OVER (ORDER BY id) AS newID,
    *
  FROM
    yourTable
)
UPDATE
  resequenced
SET
  id = newID

私は何年もこれを行っていないので、同じid値を持つ 2 つのレコードを持つことによって、更新中に問題が発生するかどうかを忘れています。もしそうなら、あなたは最初にこのようなことをすることができます...

UPDATE yourTable SET id = -id


オプション 2:

外部キー関係が明示的に定義されていないことを確認してください。存在する場合は、それらをメモして削除します。

次に、次のようなことを行います...

CREATE TABLE temp AS
  newID INT IDENTITY (1,1),
  oldID INT
)

INSERT INTO temp (oldID) SELECT id FROM yourTable

/* Do this once for the table you are re-identifiering              */
/* Repeat this for all fact tables holding that ID as a foreign key */
UPDATE
  factTable
SET
  foreignID = temp.newID
FROM
  temp
WHERE
  foreignID = temp.oldID

次に、既存の外部キー関係を再適用します。

これはかなり恐ろしいオプションです。テーブルを更新するのを忘れた場合、データが破損したことになります。ただし、そのテーブルにもっと適切な名前を付けて、それを保持することができます。temp


幸運を。そして、主があなたの魂を憐れんでくださいますように。暗い路地で彼に会ったことがあれば、ティムのことです。

于 2012-11-14T10:20:59.973 に答える
1

1 から増分 1 の最大値までのシーケンスのみを持つ数値テーブルを作成してから、visitid の maxid を取得するロジックを変更し、他の人が数値と訪問テーブルの間で正しい結合を行う可能性があります。 . そして、その数の te min を探すことができます

select min(number) from visits right join numbers on visits.id = numbers.number

そうすれば、他のテーブルを変更することなく、すべてのギャップを埋めることができます。

しかし、データベース全体をやり直すだけです。

于 2012-11-14T10:15:03.903 に答える