【问题标题】:Rails: A database-independent datatype that's suitable for bitwise operationsRails:适用于按位运算的独立于数据库的数据类型
【发布时间】:2013-06-14 19:40:35
【问题描述】:

我有一个带有几个资源的 Rails 应用程序,我需要在这些资源上运行涉及按位运算的查询。现在,我正在使用 PostgreSQL,并为我的“用户”模型创建了一个迁移,该模型使用 postgres 特定的“BIT VARYING”数据类型,因为这是在 postgres 网站上推荐的按位“&”操作:

add_column :users, :timeslots, :'BIT VARYING'

在我的一个查询中,我以这种方式使用“&”:

self.where("available_lbs > 0 AND status = 0 AND ? & timeslot > 0::bit AND available_end >= ?", user.timeslots, Time.now)

这似乎在我的机器上工作,但有两个问题:

  1. 数据类型和查询都是特定于数据库的,所以如果我迁移到另一个数据库,我可能需要进行更改
  2. 此迁移似乎没有正确更新 schema.rb 文件。在描述如何创建表时,它仍然使用 Rails 'string' 数据类型:

create_table "users", :force => true do |t|

t.string "timeslots", :limit => nil

结束

因此,当我在新机器上设置应用程序时,它使用了错误的数据类型,事情就中断了。对此有什么好的解决方案吗? (我尝试使用“二进制”数据类型,但这似乎不适用于 postgres)

【问题讨论】:

  • 这篇文章有一些关于数学的很好的信息,但它没有说任何关于处理数据库方面的内容。
  • 为什么在关系数据库中使用位运算符?这通常是一件令人讨厌的事情,您的数据库可能会因此而讨厌您。
  • 我正在尝试查找与我传入的另一个时隙字段的时隙字段的 & 为 > 0 的所有用户记录。我认为在查询中执行此操作比将它们全部拉入 Ruby 并在那里执行。
  • 但是为什么timeslot 是位图呢?为什么不使用对关系数据库更自然的表示?位图在 C 语言中是有意义的,但在其他任何地方它们几乎总是过早的优化。

标签: sql ruby-on-rails-3 postgresql bit-manipulation bit-masks


【解决方案1】:

我建议规范化数据模型:用户 --- 一对多 ---> 时隙。

这是可移植的,您可以使用所有更高级别的 SQL 函数,如窗口聚合等。

此外,您的记录是“人类可读的”,例如在即席查询中,因为它们不需要按位操作。

如果您选择位域,您通常会优化大小/内存使用,但会以性能为代价。我从未见过关于 PostgreSQL 的比较,但在微处理器/微控制器的组装级别就是这种情况:即使在内存受限的微控制器中,您通常也会选择 bool(需要一个字节,如果对齐可能需要四个字节) ,因为访问速度更快,并且需要的指令更少。而且它更容易编码和调试。

【讨论】:

  • 所有优点。我以前使用过这种方法,但是我有 168 个不同的时间段(一周中的每个小时一个),每个时间段都直接映射到我 UI 中日历上的一个单元格。如果我使用一对多关系,我需要用 168 个不同的时隙为数据库播种,然后维护一个巨大的连接表来跟踪哪些用户有哪些时隙。在我看来这是相当讨厌的,所以翻转比特似乎更干净。我想我要做的是将位域分成 7 个整数,每个整数代表一周中的不同日期。
  • 能否将您的数据模型添加到您的问题中?您的用户与时间段具有多对多关系,可能绑定到某个时间段(= 每个月/年/周等不同)?
  • 是的,是多对多的关系,但是月/年/周没有以任何方式记录,无关紧要。它只是记录每个用户在任何给定周内占用了哪些 1 小时时间段。
  • 因此,如果有 10000 个用户,每个用户/天有 10 个分配时隙,您将有 700000 行。那应该不是问题。您可以用时间范围替换“以小时为单位的时间段”,但这并不是必需的。无论这些赋值是存储在位域还是行中,逻辑数据量都是一样的。除非存在性能问题,否则我不会将其非规范化为 7 个整数。
猜你喜欢
  • 1970-01-01
  • 2018-04-07
  • 2023-03-30
  • 1970-01-01
  • 2011-02-28
  • 1970-01-01
  • 2020-11-19
  • 1970-01-01
  • 2023-03-04
相关资源
最近更新 更多