データベースでビットマスクを使用する利点と欠点


22

少し前に同僚と話をしましたが、彼はデータベースに保存されているすべての値を理解するのが難しいため、ビットマスクの使用に間違いなく反対しました。私の意見では、例えば現在のユーザーの役割を決定するためにそれらを使用することは必ずしも悪い考えではありません。それ以外の場合は、別のテーブルに保存する必要があり、これによりもう1つのJOINが発生します。私が間違っているかどうか教えてもらえますか?ビットマスクを使用する他の副作用、利点/欠点はありますか?


2
データベースで内部的にビットマスクを作成し、ビットを個別の列として表示する方が理にかなっている場合があります。要件が変更される場合があります。
サイモンリヒター

1
結合を使用しない場合、意図したとおりにリレーショナルデータベースを使用していません。
ピーターB

回答:


38

私は、ビットマスクを使用してユーザーロールの割り当てを保存するアプリケーションを使用しています。それはお尻の痛みです。もしこれが私を偏見させ、罪を犯したとしても。

リレーショナルデータベースを既に使用している場合、それはほとんどのリレーショナル理論とすべての正規化ルールに違反するアンチパターンです。独自のデータストレージを構築する場合、それほど悪い考えではないかもしれません。

結合されるテーブルが多すぎるなどの問題がありますが、これを処理するためにリレーショナルデータベースが構築されます。インデックス、インデックス付きビューなど、パフォーマンスが問題になる場合、多くの追加機能があります。検索する値がそれほど頻繁に変更されない場合でも、ビットマスクの利点は、インデックス作成を管理するオーバーヘッドがデータベース上で非常に簡単です。

データベースはデータの集計に優れていますが、データセットに複雑な数式やスカラー関数などを導入し始めると、データベースが遅くなる可能性があります。アプリでビット単位の操作を行うことはできますが、関連データを取得すること(ユーザーの役割を調べること)だけを行う場合、データストレージの最適な機能を活用することはできません。

それに対する私の最後の議論は、他の開発者にとってのシンプルさです。ユーザー、ロール、および割り当てがあります。多対多のリレーションセット(複数のリレーションがあるため)は非常に一般的であるため、管理が容易である必要があります。それはただのCRUDのものです。


8
リレーショナルデータベースは、ビットマスクの最悪の場所に関するものです。ストレージのコストはそれほど悪くないので、いくつかの結合と余分なテーブルがあなたを破壊するでしょう。それは確かにすべてについて推論するのを難しくします。権限を独自のテーブルのデータベースにビット(1/0)として保存し、フラグ付きのコードでそれらを表します。かなり適切で実行可能なようです。開発者は単純なフラグを取得し、DBAはテーブルを正規化しました。みんな幸せです。
マイクマクマホン

3
同意して、データベースのユーザーロールと特権にビットマスクを使用するアプリケーションをサポートするために使用していました。それは悪夢でした。32ビットのintを使用して、我々はビットを使い果たしたので、誰かが追加して素晴らしいアイデアを持っていたより多くのビットマスクをして、重複し、したがって、この他の列に1列意味ビット8に4ビット、そして彼らが同期していました。そうそうそう。インデックスは個々のビットではなく、個別の列値を格納するため、インデックスを作成するのは困難でした。したがってwhere some_bit_mask & 12 > 0、行ごとのスキャンなしでは行を検索できません。
ブランドン

一日の終わりには、多対多user_role_mapまたはuser_priv_mapテーブルで十分です。
ブランドン

@MikeMcMahon、テーブルの設計をさらに深く掘り下げてください。そして、あなたが話している結果を達成するために、どのようにコードでそれをマップすべきですか?
アレックスオベチキン

2
@usr-決して言わないでください。ビットマスクは使用できますが、リレーショナルデータベースを使用するアプリケーションでは使用しません。おそらく、レガシーデータを処理する場合や、速度が非常に必要な場合には、いくつかのエッジケースがあります。
ジェフ

24

あなたはすでに関連する長所と短所に名前を付けています:

  • ビットフィールドはスペースを節約します。
  • レコード自体にデータを保存するため、それらを見つけるためにJOINを必要としません。(ただし、レコード内の個々のフラグフィールドは同じことをします。)
  • 生のSQL出力を生産的に使用したい場合、これらは読みにくいです。

何をすべきかを決定するには、さらに情報が必要です。

  • ユースケースのディスクスペースはどれだけ不足していますか?
  • ユーザーロールを実際に頻繁に読んで、それらを結合する時間がボトルネックになっていますか?
  • しているあなたは、SQL出力を読み、それに基づいて意思決定を行うために行く-またはちょうどあなたのシステムのマシンコードが読めないという事実のように読めないデータ・ベース・レコード軽微であり、?

そのため、リスク要因を収集してから重みを付け、プロがデメリットを上回るかどうかを確認する必要があります。


あなたの答えをありがとう、あなたの考えに完全に同意しますが、一般的にこのアンチパターンはそうですか?また、プロジェクトでマスクを使用していますか?
アレックスオベチキン

12
@Alex あなたのケースで何をすべきかを決定できる「ベストプラクティス」のようなものはありません。スペースが極端に短い場合は、ビットフィールドを使用することをお勧めします。CEOへのレポートでSQL出力を使用する場合は、名前を話すのがベストプラクティスです。しかし、これらの状況を知っているのはあなただけなので、コミュニティは常に有効な処方箋をあなたに与えることはできません。
キリアンフォス

スペース引数を「ギミ」としてとる。ビットマスクを使用するかどうかの問題は、それ以上の利点を推測するかどうかにかかっています。
ロビーディー

また、データベース内の情報を処理する必要がありますか、それを使用する前に常にアプリケーションに読み込まれますか?
イアン

1
「SQL出力を読み取り、それに基づいて決定を下しますか、またはシステムのマシンコードが読み取れないという事実と同様に、読み取り不能なデータベースレコードは重要ではありませんか?」すべての開発者に話をすることはできないと思いますが、開発中は、DBからデータを選択して何かを理解または確認することは非常に一般的です。したがって、私は通常、これに対する答えは「はい、誰かがします」と主張します。
jpmc26

18

あなたが本当に、本当に本当にディスクスペースに縛られているなら、ユーザーパーミッションのためにビットマップを検討するかもしれません。パフォーマンスが心配な場合は、それらを完全に忘れてください。それらをバラバラにすると実際には遅くなります。ビットマップフィールドに意味のあるインデックスを作成することはできません。その結果、データベーステーブルスキャンが発生します。これは常にパフォーマンスを低下させます。

あなたがAmazonまたはNetflixでない限り、ユーザーの許可に関係するデータのは、あなたが保持している他のすべてのものと比較して無視できます。

真面目なDBMSは、明滅することなく「余分な結合」を処理できます。


7
+1:優れたリレーショナルデータベースは、自分の仕事を本当に、本当に、本当に得意とする人々によって開発されています。ビットフィールドを使用することで得られるパフォーマンスの最後のビットを絞り出す必要があるレベルの人は、質問する必要はありません。データをモデル化し、実行しない部分を見つけます。
Blrfl

結合を行うと、アプリケーションコードがより複雑になるため、ロールが処理される場所に大きく依存します。
イアン

4
結合を持つ@Ianは、ビットマスクされたアクセス許可を解読する方法を知る必要があるほど複雑ではないようです。
ブラッド

@ Brad、C#のフラグのセットである列挙型を考えてください。その値はデータベースに「そのまま」保存され、C#のコールドはこれ以上単純になりません。結合を使用する場合、C#コードは「1対多」の関係に対処する必要があります。
イアン

また、テーブルに複数のブール列がある場合、ほとんどのデータベースはそれらを可能な限り小さなスペースに押しつぶす方法を見つけ出し、あなたのためにビット調整を処理します。
Blrfl

8

ストレージが高価だった頃、ビットマスクの利点は、スペースを節約できることでした。ビッグデータの時代、これはかつての問題ではありません。

あなたが引用する例を挙げると、ビットマスクとして保存されたロールは、最初の標準形式に違反するため、データベース設計の観点からはコード臭のようなものになります。この意味で、それらはアンチパターンです。

このすべてが言われている、それはどちらかである必要はありません。データをビットマスクとして保存し、その場でユーザーロールを取得できるビューを作成できます。また、どのユーザーが同じ役割を持っているかを一目で確認できるという利点もあります。


2

ビットマスクを使用する唯一の利点は、ビットフィールドの意味が静的でない場合です。リレーショナルテーブルは、各フィールドがレコード上にあるものを事前に知っている場合にのみ機能しますCREATE TABLE。結局、DDLステートメントでフィールドを識別する必要があります。

場合は、各ビットフィールドの意味は、実行時に設定可能である、またはそれ以外の場合は事前に知られていない、それは可能性があるビットフィールドとしてブール値を格納するために意味をなします。それでも、それは任意のフィールドを持つテーブルを定義することが可能である:field_1field_2まだ理想的ではないものの、などこれは、あなたのクリーナーリレーショナル設計を提供します。どちらのソリューションも理想的ではないため、これがビットフィールドよりも優先されるかどうかは、主に意見の問題です。

開発中にビットが何を表すかがわかっている場合は、ビットごとにフィールドを作成し、意味のある名前を付けます。

内側のプラットフォーム効果に注意してください。最終的に任意のフィールドを適切に定義する場合、それは1つのことですが、それよりも大きくなりすぎると、リレーショナルデータベース内でリレーショナルデータベースを再発明することになります。


2

私はビットマスクについてあいまいです。彼らの中傷者のほとんどは、バイナリと16進数を理解していないことがわかります。明確にするために、適切なニーモニックを使用します。

上記で言及されていない利点は、時間のかかる可能性のある新しい列の追加なしに、ビットマスクに新しい意味を追加できることです。私たちのdbデザイナー(私の前にいた)がテーブルにそれらを置いて、毎日500万件の新しいレコードを取得しています。新しい列を追加して新しい動作を表すには時間がかかりますが、新しいビット(64のうち33を消費しました)を定義するためにテーブルを再構築する必要はありません。

いいえ、ビットマスクにインデックスを付けることはできませんが、33個のインデックスを作成するのはばかげているため、クロールへの挿入が遅くなります。テーブル検索では、日付とレコードの「所有者」インデックスが使用されるため、可能であれば、このビットマスクのインデックスは使用されません。


興味深いケースです。テーブルに「スペア」列を定義し、必要に応じてこれらを使用することで、同じことを明確かつ明示的な方法で実現できると思います。そうすることを選択した場合、少なくともこれらの列に選択的にインデックスを付けることができます。
スティーブ

1

目標がディスク領域を節約することだけである場合、それは悪い考えだと思います。

  • 今日のGBのコストを見て、
  • レポートとクラッカーを書き、フィールドの内容と特定のビットに対処する方法を理解する必要がある人の時間のコストと比較すると、コスト/メリットの比較は間違った側で終わる可能性があります。
  • SQLデータベースを使用している場合、多くのクエリで必要な追加のビットアクセス操作も、必要以上の計算時間を消費する可能性があります。

ただし、ビットフィールドの使用を正当化できる場合があります。

  • ビットが常に全体として一緒に処理するフラグの複雑なセットを表す場合、
  • これらのセットにパターンマッチングアルゴリズムを適用する必要がある場合は、さらに、
  • 特に、このデータが最も頻繁に使用される選択基準に含まれていない場合。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.