2

我有一张users表格,格式如下:

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

settings字段是类型number并包含设置的位掩码。

我必须支持(除其他外)查询,例如:

  • 查找所有具有 setting1、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

为您提供查询的“和”版本。

于 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;

注意 PRIMARY KEY 和 ORGANIZATION INDEX COMPRESS 子句中字段的顺序:

  • 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,这将非常快。

您还可以获取具有所有给定设置的用户,如下所示:

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 回答