37

私は好奇心からこれを求めています。基本的に私の質問は、フラグのように振る舞うものを持つために行エントリを必要とするデータベースがある場合、ベストプラクティスは何ですか? この良い例は、スタック オーバーフローのバッジ、または bugzilla のオペレーティング システム フィールドです。フラグの任意のサブセットを特定のエントリに設定できます。

通常、私は c および c++ の作業を行っているため、直感的な反応として、反転可能なビットのセットとして符号なし整数フィールドを使用することになります。最も明白なのはスケーラビリティです。使用できるフラグの数には厳密な上限があります。

また、スケーラビリティは向上しますが、すべての情報を取得するには複数の選択が必要になるため、パフォーマンスの問題が発生する他のソリューションもいくつか考えられます。

それで、これを行う「正しい」方法は何ですか?

4

8 に答える 8

33

一般的に言って、私はビットマスクフィールドを避けます。それらは将来読むのが難しく、理解するためにデータのより深い知識を必要とします。

リレーショナルソリューションは以前に提案されています。あなたが概説した例を考えると、私は次のようなものを作成します(SQL Serverで):


CREATE TABLE Users (
  UserId INT IDENTITY(1, 1) PRIMARY KEY,
  FirstName VARCHAR(50),
  LastName VARCHAR(50),
  EmailAddress VARCHAR(255)
);

CREATE TABLE Badges (
  BadgeId INT IDENTITY(1, 1) PRIMARY KEY,
  [Name] VARCHAR(50),
  [Description] VARCHAR(255)
);

CREATE TABLE UserBadges (
  UserId INT REFERENCES Users(UserId),
  BadgeId INT REFERENCES Badges(BadgeId)
);
于 2008-09-24T01:23:45.483 に答える
29

フラグの閉じたセット (たとえば、stackoverflow バッジ) からの無制限の選択が本当に必要な場合、「リレーショナルな方法」は、フラグのテーブルと、それらのフラグをターゲット エンティティに関連付ける別のテーブルを作成することです。したがって、users、flags、および usersToFlags.

ただし、スペース効率が重要な問題であり、クエリ機能がそうでない場合は、署名なしのマスクでもほぼ同じように機能します。

于 2008-09-24T01:19:03.000 に答える
5

多くの場合、データベースのバックエンドなど、多くのことに依存します。たとえば、MySQLを使用している場合、SETデータ型はまさに必要なものです。

基本的に、これは単なるビットマスクであり、各ビットに値が割り当てられています。MySQLは最大64ビット値をサポートします(64の異なるトグルを意味します)。必要なのが8つだけの場合は、1行あたり1バイトしかかかりません。これは、かなりの節約になります。

正直なところ、1つのフィールドに64を超える値がある場合、フィールドはより複雑になる可能性があります。次に、BLOBデータ型に拡張することをお勧めします。これは、MySQLが本質的に理解していない単なるビットのセットです。これを使用して、MySQLが2進数、16進数、または10進数の値として処理できる任意の数のビットフィールドを作成できますが、必要に応じて作成できます。64を超えるオプションが必要な場合は、アプリケーションに適した数のフィールドを作成してください。欠点は、フィールドを人間が読める形式にするのが難しいことです。BITデータ型も64に制限されています。

于 2008-09-24T01:19:17.413 に答える
4

非常にリレーショナルなアプローチ

セットタイプのないデータベースの場合、各フラグが設定されているエンティティのセットを表す新しいテーブルを開くことができます。

たとえば、テーブル「Students」の場合、テーブル「RegisteredStudents」、「SickStudents」、TroublesomeStudentsなどを含めることができます。各テーブルには、student_idという1つの列のみがあります。どの学生が「登録済み」または「病気」であるかを知りたいだけであれば、これは実際には非常に高速であり、すべてのDBMSで同じように機能します。

于 2008-09-26T12:21:57.373 に答える
4

フラグの意味が大きく異なり、SQL クエリまたはビューで直接使用される場合は、型の複数の列を使用するBOOLEANことをお勧めします。

いずれにせよ、それらを個別に読み取り、変更するため、各フラグを追加の列に入れます。フラグをグループ化する場合は、列名に共通のプレフィックスを付けます。つまり、次の代わりに:

CREATE TABLE ... (
    warnings INTEGER,
    errors   INTEGER,
    ...
)

あなたが使用する必要があります:

CREATE TABLE ... (
    warning_foo BOOLEAN,
    warning_bar BOOLEAN,
    warning_...
    error_foo   BOOLEAN,
    error_bar   BOOLEAN,
    error_...   BOOLEAN,
    ...
)

MySQL には BOOLEAN 型がありませんが、準標準の TINYINT(1) をその目的で使用し、0 または 1 にのみ設定できます。

于 2008-09-24T17:57:57.437 に答える
3

データベースがこれをサポートしている場合は、BOOLEAN データ型を使用することをお勧めします。

それ以外の場合、最善の方法は NUMBER(1) または同等のものを使用し、有効な値を (0,1) に制限するチェック制約を列に設定し、必要に応じて NULL にすることです。組み込み型がない場合、数値を使用すると、文字列を使用する場合よりもあいまいさがなくなります。(true の値は? "T" または "Y" または "t")

これの良いところは、SUM() を使用して TRUE 行の数をカウントできることです。

SELECT COUNT(1), SUM(ActiveFlag)
FROM myusers;
于 2008-09-25T05:40:49.447 に答える
2

フラグが数個以上ある場合、または将来そうなる可能性がある場合は、フラグの別のテーブルとそれらの間の多対多テーブルを使用します。

少数のフラグがあり、それらを WHERE で使用するつもりがない場合は、SET() やビットフィールドなどを使用します。それらは読みやすく、よりコンパクトですが、クエリを実行するのが面倒で、ORM を使用するとさらに頭痛の種になることもあります。

フラグが数個しかない場合 (フラグが数個しかない場合) は、BIT/BOOLEAN/etc 列をいくつか作成します。

于 2008-09-24T01:39:21.157 に答える