12

次の表を検討してください。

CREATE TABLE user_roles(
    pkey         SERIAL PRIMARY KEY,
    bit_id       BIGINT NOT NULL,
    name         VARCHAR(256) NOT NULL,
);

INSERT INTO user_roles (bit_id,name) VALUES (1,'public');
INSERT INTO user_roles (bit_id,name) VALUES (2,'restricted');
INSERT INTO user_roles (bit_id,name) VALUES (4,'confidential');
INSERT INTO user_roles (bit_id,name) VALUES (8,'secret');

CREATE TABLE news(
    pkey          SERIAL PRIMARY KEY,
    title         VARCHAR(256),
    company_fk    INTEGER REFERENCES compaines(pkey), -- updated since asking the question
    body          VARCHAR(512),
    read_roles    BIGINT -- bit flag 
);

read_roles は、ニュース項目を読むことができる役割の組み合わせを指定するビット フラグです。したがって、制限付きおよび機密で読むことができるニュース項目を挿入する場合、read_roles の値を2 | 46 または 6 に設定し、特定のユーザーが表示できるニュース投稿を取得したい場合は、次のようなクエリを使用できます。

select * from news WHERE company_fk=2 AND (read_roles | 2 != 0) OR  (read_roles | 4 != 0) ; 
select * from news WHERE company_fk=2 AND read_roles = 6; 

一般に、データベース列でビット フラグを使用することの欠点は何ですか? この質問に対する答えはデータベース固有のものである可能性があると想定しているため、特定のデータベースの欠点について知りたいと思っています。

アプリケーションに Postgres 9.1 を使用しています。

更新私は、データベースがビット操作にインデックスを使用しないことについて少し理解しました。これは、パフォーマンスを低下させる完全なテーブルスキャンを必要とします。データベースの各行は特定の会社に属しているため、すべてのクエリには、インデックスを持つ company_fk を含む WHERE 句が含まれます。

更新私は現在6つの役割しか持っていませんが、将来的にはさらに増える可能性があります.

UPDATEロールは相互に排他的ではなく、互いに継承します。たとえば、restricted は public に割り当てられたすべての権限を継承します。

4

4 に答える 4

9

短所: データの書き込み、データの読み取り、デバッグが困難ですが、特に: データベースがこのようなクエリでインデックスを使用できないため、クエリが遅くなります。

利点として、数バイト節約できます。BIT フィールドと比較すると、100 万レコードのテーブルで数 MB 節約できます。ほとんど価値がありません。:)

于 2012-09-04T19:58:48.493 に答える
9

少数のロールしかない場合、 PostgreSQLのストレージスペースを節約することさえできません。列は 4 バイト、8 バイトを使用します。どちらも配置パディングが必要な場合があります。integerbigint

カラムは1booleanバイトを使用します。integer事実上、1 つの列には 4 つ以上のブール列、1 つの列には 8つ以上のブール列を合わせることができますbigint

また、値はNULL ビットマップで 1 ビット (簡略化)NULLしか使用しないことも考慮してください。

個々の列は読みやすく、索引付けも容易です。他の人はすでにそれについてコメントしています。

または部分的なインデックスでインデックスを使用して、インデックスの問題を回避することもできます ("非検索引数")。次のような一般化されたステートメント:

データベースは、このようなクエリでインデックスを使用できません

また

これらの条件は SARGable ではありません。

これらの機能が欠けている他の RDBMS については、完全に正しいわけではありません。
しかし、問題を完全に回避できるのに、なぜ回避するのでしょうか?

あなたが明確にしたように、私たちは6つの異なるタイプ(おそらくそれ以上)について話している. 個々のboolean列に移動します。おそらく、1 つに比べてスペースを節約することさえできますbigint。この場合、必要なスペースは重要ではないようです。


これらのフラグが相互に排他的である場合は、型の1 つのenumまたは小さなルックアップ テーブルとそれを参照する外部キーを使用できます。(質問の更新で除外されました。)

于 2012-09-04T20:02:19.770 に答える
6

ここには少なくとも1つの大きな欠点があります...

これらの条件は SARGable ではありません。

これは大きな問題であり、私にとっては大きな問題です。実行する必要があるビット単位の評価は、(私の知る限り)どのデータベースでもインデックス化できません。エンジンは、評価を実行するためにすべての行をチェックする必要があります。これは、ひどいパフォーマンスを意味します。

于 2012-09-04T19:58:16.757 に答える
2

BIT NOT NULLSQL Server の実装に関する以前の回答に加えて、列の山に対して単一のビットフィールド整数を使用してもスペースを節約できません。

SQL Server データベース エンジンは、ビット列のストレージを最適化します。テーブル内のビット列が 8 つ以下の場合、列は 1 バイトとして格納されます。9 ~ 16ビットの列がある場合、列は 2 バイトとして格納されます。

docs.microsoft.com のビット

JNK が述べたように、ビットフィールド整数の部分比較は SARGable ではないため、値全体を一度に比較しない限り、ビットフィールド整数のインデックスは役に立ちません。

SQL Server のディスク上のインデックスは並べ替えに基づいているため、特定のビットが設定された行を分離して取得するには、ビット列ごとに個別のインデックスが必要になります。1 のみを探している場合にスペースを節約する 1 つの方法は、1 の値のみを格納するフィルター処理された列を作成することです (0 の値にはインデックス エントリがまったくありません)。

CREATE TABLE news(
    pkey          INT IDENTITY PRIMARY KEY,
    title         VARCHAR(256),
    company_fk    INTEGER REFERENCES compaines(pkey), -- updated since asking the question
    body          VARCHAR(512),
    public_role BIT NOT NULL DEFAULT 0,
    restricted_role BIT NOT NULL DEFAULT 0,
    confidential_role BIT NOT NULL DEFAULT 0,
    secret_role BIT NOT NULL DEFAULT 0
);

CREATE UNIQUE INDEX ByPublicRole ON news(public_role, pkey) WHERE public_role=1;
CREATE UNIQUE INDEX ByRestrictedRole ON news(restricted_role, pkey) WHERE restricted_role=1;
CREATE UNIQUE INDEX ByConfidentialRole ON news(confidential_role, pkey) WHERE confidential_role=1;
CREATE UNIQUE INDEX BySecretRole ON news(secret_role, pkey) WHERE secret_role=1;

select * from news WHERE company_fk=2 AND restricted_role=1 OR confidential_role=1; 
select * from news WHERE company_fk=2 AND restricted_role=1 AND confidential_role=1;

これらのクエリは両方とも、私が作成したランダムなテスト データを使用して優れた計画を作成します。 ビットプラン

いつものように、インデックスは実際のクエリの使用状況に基づいており、メンテナンス コストとのバランスを取る必要があります。

于 2018-06-20T16:25:09.203 に答える