2

私はusers次の形式のテーブルを持っています:

users(id,name.....,settings)

settingsフィールドはタイプnumberであり、設定のビットマスクが含まれています。

私は(とりわけ)次のようなクエリをサポートする必要があります:

  • settings1、setting23、setting125を持つすべてのユーザーを検索します

今日、そのようなクエリは次のようになります。

 select * from users where bit_and(settings,2^1+2^23+2^125) = 2^1+2^23+2^125

もちろん、これは完全な実装ではありませんが、すでに多くの時間このように機能しています。

問題は、今日、126の異なる設定があり、それがoracle 11gビット単位の演算の限界であるということです。つまり、新しい設定を追加することはできなくなります。

私はこの問題の代替解決策を見つけようとしています。明らかな方法は、フィールドを設定する代わりに、次のようにマッピングのテーブルを作成することです(ユーザー->設定)。

user_id | setting
  128   |   1
  128   |   23
  128   |   125

しかし、上記のようなクエリは次のようになります:

select * 
from users u1 join settings s1 on u1.id = s1.user_id and s1.setting  = 1
              join settings s2 on u1.id = s2.user_id and s2.setting  = 23
              join settings s3 on u1.id = s3.user_id and s3.setting  = 125

見栄えが悪い...

したがって、誰かがこの問題の解決策/アプローチをアドバイスできる場合、それは非常に役立ちます...

4

3 に答える 3

3

これが関連する質問に対する私の答えです

クエリを簡単に簡略化できます。

select * 
from  users     u 
join  settings  s 
on    u.id = s1.user_id 
and   s1.setting  in (1, 23, 125)

これにより、クエリの「または」バージョンが得られます。

select u.userid, sum(s.setting) 
from  users     u 
join  settings  s 
on    u.id = s1.user_id 
and   s.setting  in (1, 23, 125)
group by u.userid
having sum(s.setting) = 149

クエリの「and」バージョンを提供します。

于 2012-11-06T11:00:57.667 に答える
1

新しいデザインは基本的には問題ありませんが、「特定の設定のユーザーを取得する」が主なクエリであると仮定すると、次の方法で微調整できます...

CREATE TABLE "user" (
    user_id INT PRIMARY KEY
    -- Other fields ...
);

CREATE TABLE user_setting (
    setting INT,
    user_id INT,
    PRIMARY KEY(setting, user_id),
    CHECK (setting BETWEEN 1 AND 125),
    FOREIGN KEY (user_id) REFERENCING "user" (user_id)
) ORGANIZATION INDEX COMPRESS;

PRIMARYKEYおよびORGANIZATIONINDEXCOMPRESS句のフィールドの順序に注意してください。

  • ORGANIZATION INDEXは、同じ。を持つ行をクラスター化します(物理的に近くに格納します)setting
  • settingCOMPRESSは、繰り返されるフィールドのストレージ(およびキャッシング!)コストを最小限に抑えます。

次に、このような特定の設定のいずれかにユーザーを接続させることができます...

SELECT * FROM "user"
WHERE user_id IN (
    SELECT user_id FROM user_setting
    WHERE setting IN (1, 23, 125)
);

...これは、優れたインデックス作成と最小化されたI/Oのおかげで非常に高速になります。

次のようなすべてのgive設定を持つユーザーを取得することもできます。

SELECT * FROM "user"
WHERE user_id IN (
    SELECT user_id
    FROM user_setting
    WHERE setting IN (1, 23, 125)
    GROUP BY user_id
    HAVING COUNT(setting) = 3
);

すべての設定にビットフィールドを使用すると、クエリが煩雑になり、クエリのパフォーマンスを最適化するのが難しくなります(古い設計では、すべてのクエリがテーブルスキャンです!)。OTOH、「設定ごとの列」の設計では、パフォーマンスを向上させるために列ごとに個別のインデックスが必要になりますが、それでもエレガントではないクエリがいくつかあります。

また、これらのアプローチは柔軟性がありません。新しいデザインを簡単に拡張して、より多くの設定を受け入れたり、別のテーブルを追加してから参照することで各設定に関する追加情報を(番号だけでなく)保存したりできますuser_setting

于 2012-11-06T13:41:07.130 に答える
0

各設定を独自の列に保存します。

于 2012-11-06T08:52:15.777 に答える