2

2 つの基本的な制約 (一意キーと外部キー) を強制するためのサポートの欠如が、困難な問題のデバッグとトラブルシューティングに多くの工数を失う理由になっているようです。些細で簡単に修正できる問題 (行の重複/主詳細表の不整合) として始まったものは、気付かれずに成長し、アプリケーションやハードウェアで複雑なエッジ シナリオが発生します (例: 重複による自己結合)膨張や貯蔵の枯渇を引き起こす可能性があります)。

  • Netezza は、本番環境、研究、QA、およびステージングなど、当社の環境で複数の目的を果たします。当然のことながら、私たちの ETL プロセスは成熟することはできず、これらすべてのシナリオですべての制約を検証することはできません。
  • ETL がデータをロードしている間にデータが検証される、本番環境で使用される最も成熟したアプリケーションでさえ、一連のテーブルを作成し、それぞれが前任者の計算結果になります。最初からではなく、途中でデータの整合性が損なわれることがあります (バグのあるステートメントの結果として)。

これらの頭痛を回避するための方法論/ツールを推奨できる人はいますか?

4

4 に答える 4

5

別のアプローチに貢献したかったのですが、受け入れられた答えがあることは理解しています。現在の役職に就いたばかりの私は、倉庫内の主キー宣言の背後にあるすべてのビジネス上の決定に関与しているわけではありません。重複行の削除作業を経時的に追跡するロギング タイプのアプローチを開発しました。このデザインの主な特徴は次のとおりです。

  • DDL / DML の流動的な性質に対処し、常に最新の状態に保つ
    • 新しい/削除されたテーブル
    • 新規/更新された主キー
    • 新規/更新/削除された行
  • 自己入力履歴
    • 経時的な改善を追跡
    • すべてのレベルでトレンド分析の基礎を提供
  • 調査目的でターゲット テーブルを簡単にクエリする
    • HAVING 句による自己結合やキー列のルックアップは不要
  • 現時点では主キーのみに対応
    • Unique 制約に対処するために簡単に拡張できます (CONTYPE = 'u' in _V_RELATION_KEYDATA)

以下は、Netezza の観点から必要なすべてのものです。指摘されている場合、動的 SQL を作成するにはギャップを埋める必要があります。

最初に、すべての重複レコードのデータベース、テーブル、および内部 ROWID を追跡するテーブルを作成しました。

CREATE TABLE
    NZ_DUPLICATE_PKS
    (
        DATABASE_NAME CHARACTER VARYING(128) NOT NULL
        ,TABLE_OWNER CHARACTER VARYING(128) NOT NULL
        ,TABLE_NAME CHARACTER VARYING(128) NOT NULL
        ,ROW_ID BIGINT NOT NULL
        ,CURRENT_RECORD_INDICATOR CHARACTER(1) NOT NULL
        ,CREATE_TIMESTAMP TIMESTAMP NOT NULL
        ,LAST_UPDATE_TIMESTAMP TIMESTAMP NOT NULL
    )
DISTRIBUTE ON
    (
        ROW_ID
    );

: 分散キーの YMMV と、テーブルに入る行のボリューム。私たちの Netezza アプリケーションの行 ID は、Mustang ベースの NPS 10050 で十分に機能する、十分に自然な分布を持っていました。

次に、このテーブルのステージング バージョンが作成されました。

CREATE TABLE
    STG_NZ_DUPLICATE_PKS
    (
        DATABASE_NAME CHARACTER VARYING(128)
        ,TABLE_OWNER CHARACTER VARYING(128)
        ,TABLE_NAME CHARACTER VARYING(128)
        ,ROW_ID BIGINT
        ,CURRENT_RECORD_INDICATOR CHARACTER(1)
        ,CREATE_TIMESTAMP TIMESTAMP
        ,LAST_UPDATE_TIMESTAMP TIMESTAMP
    )
DISTRIBUTE ON
    (
        ROW_ID
    );

次に、システム ビューから動的クエリを作成して、ステージング テーブルをシードしました。これが私が始めたベースクエリです:

SELECT
    DATABASE
    ,OWNER
    ,RELATION
    ,CONSTRAINTNAME
    ,ATTNAME
FROM
    {YOUR_DATABASE_NAME}._V_RELATION_KEYDATA
WHERE
    CONTYPE = 'p'
    -- Exclude the duplicate tracking table
    AND RELATION != 'NZ_DUPLICATE_PKS'
ORDER BY
    DATABASE
    ,OWNER
    ,RELATION
    ,CONSTRAINTNAME
    ,CONSEQ
;

ここで、ベース クエリをループ処理して、挿入クエリを動的に作成します。私のショップでは DataStage を使用していますが、そのアプローチは難解であり、ここで説明する価値はありません。

: ここでは、動的 SQL をループして構築するために少し作業が必要です。シェル、Perl、Python などの無数のフレーバーを使用できます。2 つの列キーを持つサンプル テーブルを使用して、ステージング テーブルに挿入するために作成するものを次に示します。

INSERT
INTO
    STG_NZ_DUPLICATE_PKS
    (
        DATABASE_NAME
        ,TABLE_OWNER
        ,TABLE_NAME
        ,ROW_ID
        ,CURRENT_RECORD_INDICATOR
        ,CREATE_TIMESTAMP
        ,LAST_UPDATE_TIMESTAMP
    )
SELECT
    '{YOUR_DATABASE_NAME}' DATABASE_NAME
    ,'{YOUR_TABLE_OWNER}' TABLE_OWNER
    ,'{YOUR_TABLE_NAME}' TABLE_NAME
    ,DUPS.ROWID ROW_ID
    ,'Y' CURRENT_RECORD_INDICATOR
    ,CURRENT_TIMESTAMP CREATE_TIMESTAMP
    ,CURRENT_TIMESTAMP LAST_UPDATE_TIMESTAMP
FROM
    {YOUR_TABLE_NAME} DUPS
    INNER JOIN
        (
            SELECT
                {KEY_COLUMN_1}
                ,{KEY_COLUMN_2}
            FROM
                {YOUR_TABLE_NAME}
            GROUP BY
                {KEY_COLUMN_1}
                ,{KEY_COLUMN_2}
            HAVING
                COUNT(*) > 1
        )
        KEYS
        ON
            DUPS.{KEY_COLUMN_1} = KEYS.{KEY_COLUMN_1}
            AND DUPS.{KEY_COLUMN_2} = KEYS.{KEY_COLUMN_2};

すべてのテーブルをループしてステージング テーブルをシードした後、一連のクエリを実行し、データベース、所有者、テーブル名、および行 ID をゆっくりと変化するディメンションのように扱います。このクエリの終了日は、ステージング テーブルに存在しないターゲット テーブルのレコードです。

UPDATE
    NZ_DUPLICATE_PKS
SET
    CURRENT_RECORD_INDICATOR = 'N'
    ,LAST_UPDATE_TIMESTAMP = CURRENT_TIMESTAMP
WHERE
    CURRENT_RECORD_INDICATOR = 'Y'
    AND
    (
        DATABASE_NAME
        ,TABLE_OWNER
        ,TABLE_NAME
        ,ROW_ID
    )
    NOT IN
    (
        SELECT
            DATABASE_NAME
            ,TABLE_OWNER
            ,TABLE_NAME
            ,ROW_ID
        FROM
            STG_NZ_DUPLICATE_PKS
    )
;

最後に、最新のレコードをターゲット テーブルに挿入します。

INSERT
INTO
    NZ_DUPLICATE_PKS
    (
        DATABASE_NAME
        ,TABLE_OWNER
        ,TABLE_NAME
        ,ROW_ID
        ,CURRENT_RECORD_INDICATOR
        ,CREATE_TIMESTAMP
        ,LAST_UPDATE_TIMESTAMP
    )
SELECT
    DATABASE_NAME
    ,TABLE_OWNER
    ,TABLE_NAME
    ,ROW_ID
    ,CURRENT_RECORD_INDICATOR
    ,CREATE_TIMESTAMP
    ,LAST_UPDATE_TIMESTAMP
FROM
    STG_NZ_DUPLICATE_PKS
WHERE
    (
        DATABASE_NAME
        ,TABLE_OWNER
        ,TABLE_NAME
        ,ROW_ID
    )
    NOT IN
    (
        SELECT
            DATABASE_NAME
            ,TABLE_OWNER
            ,TABLE_NAME
            ,ROW_ID
        FROM
            NZ_DUPLICATE_PKS
        WHERE
            CURRENT_RECORD_INDICATOR = 'Y'
    )
;

: 当方の環境では、挿入のみのモデルが必要なわけではありません。Netezza のベテランは、この考え方に精通しています。環境が挿入のみの場合は、それに応じて戦略を調整してください。

すべてが整ったら、調査のために重複する行を見つけるのは簡単です。

SELECT
    *
FROM
    {YOUR_TABLE_NAME}
WHERE
    ROWID IN
    (
        SELECT
            ROW_ID
        FROM
            NZ_DUPLICATE_PKS
        WHERE
            CURRENT_RECORD_INDICATOR = 'Y'
            AND DATABASE_NAME = '{YOUR_DATABASE_NAME}'
            AND TABLE_OWNER = '{YOUR_OWNER_NAME}'
            AND TABLE_NAME = '{YOUR_TABLE_NAME}'
    );

主キー宣言の違いに関係なく、シンプルですべてのテーブルで同じであるため、これが気に入っています。

また、このクエリを頻繁に使用して、現在の主キー違反をテーブルごとに表示します。

SELECT
    DATABASE_NAME
    ,TABLE_OWNER
    ,TABLE_NAME
    ,COUNT(*) QUANTITY
FROM
    NZ_DUPLICATE_PKS
WHERE
    CURRENT_RECORD_INDICATOR = 'Y'
GROUP BY
    1
    ,2
    ,3
ORDER BY
    1
    ,2
    ,3;

それはすべてを要約します。一部の人々がそれを便利だと思うことを願っています。私たちはすでにこのアプローチで多くの進歩を遂げています。この時点で、なぜ私がこのようなトラブルを起こしたのか疑問に思われるかもしれません。私は PK 違反が私たちの倉庫に持ち込まれることを嫌悪しており、それらを根絶するための包括的なアプローチを望んでいました. 上記のプロセスは、数か月間、本番環境で毎日実行されています。主キーが宣言された最大 350 個のテーブルがあり、サイズは 5 行ディメンションから最大 2 億行ファクト @ 10Gb までの範囲です。Netezza にとって、これはかなり控えめな出費です。Mustang NPS 10050 では、プロセス全体に 10 分もかかりません。

于 2012-11-28T16:54:27.750 に答える
2

私たちはもともと、データ ウェアハウスでまさにこれを処理するためのストアド プロシージャを作成しました。
理論的には機能しますが、NZ で一般的に見られる巨大なテーブルの場合は少し遅くなります (500M レコード テーブルで約 10 分)。

以下でストアド プロシージャについて説明しますが、増分/アップサート ロードは、ターゲット データベースにまだ存在しないレコードのみを明示的に挿入するため、現時点では proc を活用していないことを言いたいと思います。(アップサートの場合、基本的には、挿入する前に挿入するレコードのセットに存在するレコードを削除するだけです)。

これには独自の問題があります。特に NZ は削除を好まず、実際にスペースを再利用するためにテーブルを常にグルーミングする必要があるためです。また、変更された古いレコードを削除することでアップサートが履歴列データを失う可能性があるという事実は言うまでもありません。 (追跡したいゆっくりと変化するディメンションをロードするためのプロセスは他にもあります。)

とにかく、制約ストアド プロシージャは次のようになります。

check_constraints('table','constraint_type') returns boolean

そして基本的にループします:

  select constraintname, contype, attname
    from _v_relation_keydata
   where relation = upper(p_table) order by constraintname, conseq;

比較する必要がある列を取得します。制約ごとに、次のように実行されます。

  select count(*) 
    from ( 
    select distinct col1,col2,...
      from p_table 
     where col1 is not null 
       and col2 is not null... );

その数を比較して

  select count(*) 
    from p_table 
   where col1 is not null 
     and col2 is not null...;

それらが異なる場合は、例外が発生します。

于 2011-04-23T01:18:58.577 に答える
1

制約を適用したい列のハッシュ値である列を追加してみませんか? NZ SQL 拡張機能パッケージには、ハッシュ関数があります。'key' が制約された列値の連結 (varchar にキャスト) である hash8('key') を使用すると、おそらく一意の BIGINT 値が得られます。私が「おそらく」と言ったのは、ハッシュの衝突の確率が有限であるためです。一意性のより強力な保証が必要な場合は、代わりに暗号レベルの「hash()」関数を使用できます。

ただし、非常に大量のデータがない限り、hash8 を選択することをお勧めします。整数値を与えるため、行の比較は単純な算術の問題であり、高速です。たとえば、ハッシュ値に基づいて行を更新または挿入できます。これは単なる整数比較です。

于 2014-03-07T12:16:54.757 に答える
0

Netezza はデータ ウェアハウスです。PK、FK、制約、UK、SK などはありません。これはデータ ウェアハウスです。想定されていません。MPP 分散型であるため、すべてのテーブルはフラット テーブルにする必要があります。配布キーを検索します。パーティショニングのみ。これは並列処理であり、Map Reduce に少し似ています。結合をリレーショナル データベース (キー、インデックスを含む) に配置し、フラット化されたテーブルを Netezza に移動します。https://docs.microsoft.com/en-us/sql/analytics-platform-system/staging-database?view=aps-pdw-2016-au7#:~:text=A%20staging%20database%20is%20a ,is%20loaded%20into%20the%20appliance.&text=For%20example%2C%20an%20ELT%20process,into%20the%20target%20fact%20table. Netezza でデータ モデリングを行わないでください。オラクルを使用します。Netezza には主キーと外部キーの制約があり、場合によっては一意のキーさえありますが、それらは非アクティブになっています。これも意図的なものです。テーブル全体ですべてを並行して実行するように調整されています。Snowflake は、水平方向と垂直方向の両方に分割されているという点でより寛容であり、さらにクラスター化されたような並列処理を備えているため、並列で非常に高速に実行されます (Netezza ほど良くないか、安価である可能性があります) が、Snowflake の方がはるかに優れている可能性があります。フィルタリング中。

「私たちのウェアハウスでの主キー宣言の背後にあるビジネス上の決定」の上にコメントがあるので、それらの決定を下す人々は上記のコメントです。もちろん、インデックスを持つ Exadata でウェアハウスを構築しない限り、すべてのインデックスを削除した Exadata データベースが大幅に高速化されていることを私は知っています。

于 2021-10-15T19:44:34.797 に答える