web-dev-qa-db-ja.com

ルックアップテーブルを含むビットマスクフラグの説明

Varcharとしていくつかのビットマスクフィールドを含む外部ソースからデータセットを受け取りました。長さは3から21値まであります。 ANDまたはORロジックを使用して、これらのフィールドに基づいてSELECTクエリを実行できるようにする必要があります。

計算フィールドを使用して、ビットを整数値に変換するだけで、単純なWHERE rowvalue = requestvalueを使用して、ANDクエリに一致する行を簡単に見つけることができますが、ORロジックは一致するレコードを検索するには、ビットごとの&を使用する必要があります。

これらの列のいくつかを操作して何億ものレコードから選択する必要がある場合、ビット単位の&演算を実行してSELECTの結果をフィルター処理すると、パフォーマンスが大幅に低下すると感じます。

私は この答え を検索から見つけました、それは私のニーズに合うように見えましたが、それがどのように実装されているかについていくつかの説明が必要です。

これは、すべての可能な検索条件を含むルックアップテーブルを作成するのと同じくらい簡単ですか?

(a&b)を使用した3ビットの例(編集:Wrong bitwise op)

001,001
001,011
001,101
001,111
010,010
010,011
010,110
011,011
011,111
etc

著者は最初は直感に反していると述べていますが、何十億行もある単一のルックアップテーブルが得られるため、ソリューションを誤って解釈していると感じざるを得ません。

上記でリンクした回答の説明や、既存のデータベースを維持するための他の提案はありがたいです。

編集:小さなデータを使用したより具体的な例。

4つのフラグ、HasHouse、HasCar、HasCat、HasDog、0000はなし、1111はすべてです。

すべてからなしまで、任意の数のフラグを反転できます。選択がすべてに一致する場合(正確な値の比較を使用)または少なくとも1つに一致する場合(ビットごとの&を使用)、結果をフィルターする必要があります。

各ビットマスクに単一の計算された列を追加することは問題ありませんが、100ビットを超える各ビットに列を追加することと、データを挿入/更新する方法が相まって、別の解決策を見つけようとしています。

6
mindreave

私はアーロンのコメントに部分的に同意します-関係のない21個の情報を格納する最も一般的なケースでは、おそらく21ビットの列を使用します。一般的な解決策として、それはあなたの最善の解決策になるでしょう。複数のビットマスクされたvarchar列がある場合、それは100ビットを超えるフラグを持つ行に変換されます。参考までに、NULLビットとして定義しない場合、21ビットは3バイトとして格納されるため、NULLビットマップ内のスペースは不要になります。複数のビットマスク列があるので、8ビットごとに1つのバイトにマッシュされます。

SQL Serverが複数列のクエリで最終的に行うのは、最終的には一連のビットマスキングルーチンです(そうです。SQLServerはビットマスクを使用するため、それらの概念自体が悪いわけではありません!)が、平均的なユースケースでは、あなたのために簡単。

実行するクエリのタイプに関する詳細情報がある場合は、最終的にユースケースが設計を決定するため、より適切にアドバイスできる可能性があります。

COMPUTED列を保持している場合は、永続化してインデックス付けします。次のようなsomeクエリに役立ちます

  1. 完全一致

    WHERE ComputedInt = POWER(2、6)-ビット位置7

  2. 15番目のビットでのANDマッチングとOR他の2ビットでのマッチング(10番目と7番目)

    WHERE ComputedInt> = Power(2,14)AND ComputedInt <Power(2,15)AND ComputedInt&(Power(2,9)+ Power(2,6))> 0

しかし、これらはおそらくエキゾチックなサンプルですが、場合によっては実際のライブでもあります。これは確かに21の個々のビット列よりもそれほど悪くはありません。そのため、ステートメントを記述しやすくなる可能性がありますが、SQL Serverがそれらを3バイトに格納するためにマッシュして、ビットを実行することに注意してください。とにかくアンマスキング!ビットマスキングがすべて悪い(例外なし)である場合、SQL Serverは考えませんでした。やってるよね?

[〜#〜]編集[〜#〜]

のシナリオについて

4つのフラグ、HasHouse、HasCar、HasCat、HasDog、0000はなし、1111はすべてです。

4つのビットすべてを一度にテストし、単一の整数ベースの演算を実行する方が効率的で論理的に便利です。

WHERE computedInt & (POWER(2,10)+POWER(2,5)+POWER(2,3)+POWER(2,1)) = 0 -- has none
WHERE computedInt & (POWER(2,10)+POWER(2,5)+POWER(2,3)+POWER(2,1)) > 0 -- has one or more

仮に、これがテーブルで最も実行されたクエリである場合、4つの列を別の計算された列にグループ化して個別にインデックスを付け、ビットマスクを不要にすることもできます(=0>0で結果のintをテストするだけです)。さらに進んで、答えを事前に計算することもできます...コースの馬。

1
孔夫子

私は間違いなく、ビットをルックアップテーブルにグループ化することを検討します。インポートされたデータの目的が分析である場合、データマートの例は次のとおりです。

    CREATE TABLE dbo.dimPet(
        dimPetKey SMALLINT NOT NULL IDENTITY PRIMARY KEY,
        HasCat BIT NOT NULL,
        HasDog BIT NOT NULL,
        HasHorse BIT NOT NULL
    )

    CREATE TABLE dbo.dimFamily(
        dimFamilyKey SMALLINT NOT NULL IDENTITY PRIMARY KEY,
        HasChildren BIT NOT NULL,
        HasTeens BIT NOT NULL,
        HasMultipleGenerations BIT NOT NULL
    )

    CREATE TABLE dbo.fctMainTable (
        id INT NOT NULL IDENTITY PRIMARY KEY,
        --demographic dimintions 
        dimPetKey SMALLINT NOT NULL FOREIGN KEY REFERENCES dbo.dimPet(dimPetKey),
        dimFamilyKey SMALLINT NOT NULL FOREIGN KEY REFERENCES dbo.dimFamily(dimFamilyKey),
    )

これは、データの可読性とインデックス作成の間に含まれます。

1
Matt