10

5,651,744 行のテーブルがあり、主キーは 6 列 (int x 3、smallint、varchar(39)、varchar(2)) で構成されています。このテーブルと、この主キーを共有する別のテーブルと追加の列が追加されていますが、37m 行ある別のテーブルでパフォーマンスを改善したいと考えています。

ハッシュ キーを作成するための列を追加することを見越して、分析を行ったところ、18,733 の衝突が見つかりました。

SELECT  SUM(CT)
FROM    (
         SELECT HASH_KEY
               ,COUNT(*) AS CT
         FROM   (
                 SELECT CHECKSUM(DATA_DT_ID, BANK_NUM, COST_CTR_NUM,
                                 GL_ACCT_NUM, ACCT_NUM, APPN_CD) AS HASH_KEY
                 FROM   CUST_ACCT_PRFTBLT
                ) AS X
         GROUP BY HASH_KEY
         HAVING COUNT(*) > 1
        ) AS Y

SELECT  COUNT(*)
FROM    CUST_ACCT_PRFTBLT

約2倍悪いBINARY_CHECKSUM()

私がカバーしている宛先スペースの相対的な量が少ないことを考えると、これは高すぎるように見えますか (.33%)? また、衝突がこれほど多い場合、時折の衝突を処理するために通常の列で結合する必要があることを考えると、行ごとに余分な 4 バイトのコストをかけて結合で最初にこの製造されたキーで結合する利点はありますか?

4

5 に答える 5

8

チェックサムを追加すると、そのレベルの衝突で何かが得られる場所がわかりません。衝突が 1 つでも多すぎると、間違ったデータに参加することになります。正しいレコードに結合することを保証できない場合、パフォーマンスが向上してもデータの整合性が損なわれては意味がありません。これは財務データのように見えるので、クエリが悪い結果を返さないことを十分に確認する必要があります。競合がある場合、実際には間違った口座に引き落としまたは入金することになる可能性があります。

もしあなたがこの道をたどるなら、Marc は正しく、可能な限り事前計算を行うべきです (私の経験では、数百万のレコード テーブルのすべてのレコードに発生しなければならない計算を追加しても、パフォーマンスが向上する可能性は低いです)。おそらく、事前計算された列を実行できる場合 (およびそれを最新の状態に保つためにトリガーが必要になる場合)、衝突を避けるために他の 6 つの列すべてに結合する必要はないかもしれません。その後、パフォーマンスが向上した可能性があります。あなたにできることは、あなたの理論をテストすることだけです。ただし、衝突がないことを十分に確認してください。

代理キーを使用し、代わりに 6 つの自然キー フィールドで一意のインデックスを使用することを検討しましたか? 次に、代理キーに参加すると、パフォーマンスがかなり向上する可能性があります。1 つの代理キーの代わりに 6 つの列 (1 つは varchar) で結合するのは効率的ではありません。データのサイズからわかるように、これは非本番システムよりもリファクタリングが難しいかもしれませんが、永続的なパフォーマンスの問題を永続的に修正するためにダウンタイムを費やす価値があるかもしれません. これがどれほど複雑な変更であり、すべての sps またはクエリをより適切な結合に変更するのがどれほど難しいかを言えるのは、あなただけです。ただし、試すことは可能かもしれません。

于 2009-06-22T20:52:24.493 に答える
7

これまで多くの人が口を閉ざしているのを見てきたのは、 Microsoft 自身が認めCHECKSUMたように、大量の衝突があるということです。意味のある衝突がかなりの割合で発生するよりもさらに悪いです。MD5

HASHBYTESハッシュ列を取得する場合は、 with SHA1specified の使用を検討してください。またはSHA1よりもはるかに意味のない衝突があります。したがって、行が一意であるかどうかを判断するために使用するべきではなく、2 つの値の忠実度を簡単に確認するために使用してください。したがって、行が重複していない限り、衝突率は 0% である必要があります (これは PK であるため、発生することはありません)。MD5CHECKSUMCHECKSUMHASHBYTES

8000 バイトを超えるものはすべて切り捨てられHASHBYTESますが、PK はそれよりもはるかに小さい (すべて連結されている) ため、問題はないはずです。

于 2009-07-06T10:43:31.407 に答える
2

チェックサムがデータの 0.33% まで下がった場合、特にこの列を他の (インデックス付き) 列と組み合わせて使用​​する場合は、正常に機能していると言えます。

もちろん、インデックスとして有効にするには、非クラスター化インデックスを使用して、データを挿入/更新するときにこの値を計算して保存する必要があります。

もちろん、問題の列に対する通常のスパンインデックスは、同じかそれ以上にうまくいくかもしれません...

于 2009-06-22T19:45:43.367 に答える
1

クエリが選択的であり、行テーブルのクラスター化インデックスが狭いか存在しない場合、行テーブルのチェックサムの非クラスター化インデックスは良好なパフォーマンスを提供するはずです。

ヘッダー テーブルに存在する条件を適用した後、チェックサムを使用して、非クラスター化インデックスでインデックス シークを実行します。結合に FK を含める必要がありますが、チェックサム以外の結合条件は、インデックス シーク後、ブックマーク ルックアップ後に適用されます。非常に効率的です。

インデックス シークを最適化したい。チェックサムはすでに非常に選択的です。FK を追加すると、インデックス サイズと対応する I/O が増加し、ブックマーク ルックアップを完全に回避するのに十分な数の他のフィールドが含まれていない限り、役に立ちません。

非クラスター化インデックスにはクラスター化キーまたはヒープ ポインターが含まれるため、a) 小さなクラスター化キー (たとえば、int ID 列 - 4 バイト ポインター)、または b) クラスター化インデックスがまったくない (8 バイト ポインター) のいずれかが必要です。 .

クエリが選択的でない場合、または行テーブルのクラスター化インデックスが巨大な場合 (テーブル全体からいくつかの列を差し引いたもの)、チェックサムが役立つかどうかはわかりません (インデックス ナビゲーションの高速化、おそらく?)。いずれにせよ、クラスター化インデックスまたはカバリング インデックスにしたいでしょう。ヘッダー テーブルが最初にチェックサムでクラスター化されていない場合は、多くの並べ替えが行われます。

ストレージとインデックス作成のコストに余裕がある場合は、いくつかのカバー インデックス (ヘッダーと詳細) を使用することをお勧めします。

于 2009-06-24T03:24:26.763 に答える
1

クラスターPRIMARY KEY化されている場合、作成する各インデックスにはこれが含まれますPRIMARY KEY

ハッシュ値で結合するには、次の手順を使用します。

  1. インデックス キーでハッシュ値を見つける
    • PRIMARY KEYインデックス データで値を見つける
    • テーブル内の行Clustered Index Seekを検索するために使用しますPRIMARY KEY

a に参加するPRIMARY KEYと、ステップのみが使用されます3

SQL Server、ただし、これを考慮に入れるのに十分スマートであり、次のように参加する場合:

SELECT  *
FROM    main_table mt
JOIN    CUST_ACCT_PRFTBLT cap
ON      cap.HASH_KEY = mt.HASH_KEY
        AND cap.DATA_DT_ID = mt.DATA_DT_ID
        AND …
WHERE   mt.some_col = @filter_value

のインデックスを使用せずHASH_KEY、代わりに singleClustered Index Seekと aFilterを使用して、ハッシュ値が一致することを確認します (常に一致します)。

まとめ: に参加するだけPRIMARY KEYです。

セカンダリ インデックスを使用すると、最初に無駄なHASH_KEY検索を行う必要があり、その後でPRIMARY KEY.

于 2009-06-24T16:00:48.420 に答える