В Rails, как лучше всего хранить несколько логических атрибутов в модели? - PullRequest
16 голосов
/ 10 сентября 2010

У меня есть модель House, которая имеет много логических атрибутов, таких как has_fireplace, has_basement, has_garage и так далее.House имеет около 30 таких логических атрибутов.Каков наилучший способ структурировать эту модель для эффективного хранения и поиска в базе данных?

Я хотел бы в конечном итоге найти все Houses, например, с камином и гаражом.Я полагаю, что наивным способом было бы просто добавить 30 логических атрибутов в модель, каждый из которых соответствует столбцу в базе данных, но мне любопытно, есть ли лучшая практика Rails, о которой я не знаю.

Ответы [ 8 ]

16 голосов
/ 10 сентября 2010

Ваше «наивное» предположение верно - наиболее эффективный способ с точки зрения скорости и производительности запроса - добавить столбец для каждого флага.

Вы могли бы проявить фантазию, как описали некоторые другие, но если вы не решаете некоторые очень специфические проблемы с производительностью, это не стоит усилий. В итоге вы получите систему, которую сложнее поддерживать, она менее гибка и требует больше времени для разработки.

7 голосов
/ 10 сентября 2010

Для такого количества логических значений в одной модели вы можете рассмотреть возможность использования целочисленных и побитовых операций для представления, хранения и извлечения значений.Например:

class Model < ActveRecord::Base
  HAS_FIREPLACE = (1 << 0)
  HAS_BASEMENT  = (1 << 1)
  HAS_GARAGE    = (1 << 2)

  ...
end

Тогда какой-нибудь атрибут модели с именем flags будет установлен следующим образом:

flags |= HAS_FIREPLACE
flags |= (HAS_BASEMENT | HAS_GARAGE)

И протестирован так:Вы могли бы абстрагироваться в методы.Должна быть довольно эффективной во времени и пространстве как реализация

5 голосов
/ 10 июля 2012

Я предлагаю самоцвет flag_shih_tzu . Это поможет вам хранить множество логических атрибутов в одном целочисленном столбце. Он дает вам именованные области действия для каждого атрибута и способ связать их вместе как отношения активных записей.

4 голосов
/ 10 сентября 2010

Вот еще одно решение.

Вы можете сделать модель HouseAttributes и настроить двустороннюю has_and_belongs_to_many ассоциацию

# house.rb
class House
  has_and_belongs_to_many :house_attributes
end

# house_attribute.rb
class HouseAttribute
  has_and_belongs_to_many :houses
end

Тогда каждый атрибут для дома будет записью в базе данных.

Не забудьте настроить таблицу соединений в вашей базе данных.

3 голосов
/ 10 сентября 2010

Если вы хотите запросить эти атрибуты, то, к сожалению, вы, вероятно, застряли с первоклассными полями, если производительность является фактором.Битовые поля и строки флагов - это простой способ решения проблемы, но они плохо масштабируются по отношению к производственным наборам данных.

Если вы не будете беспокоиться о производительности, я бы использовал реализацию, в которойкаждое свойство представлено символом ("a" = "garage", "b" = "камин" и т. д.), и вы просто строите строку, которая представляет все флаги, которые имеет запись.Основное преимущество, которое это имеет над битовым полем, состоит в том, что а) человеку легче отлаживать, и б) вам не нужно беспокоиться о размере ваших типов данных.

Если производительность важна,тогда вам, вероятно, нужно будет продвигать их в первоклассные поля.

2 голосов
/ 10 сентября 2010

Обычно я бы согласился, что ваше наивное предположение верно.

Если число логических полей продолжает расти и расти (has_fusion_reactor?), вы также можете рассмотреть сериализацию массив флагов

# house.rb
class House
  serialize :flags
  …
end

# Setting flags
@house.flags = [:fireplace, :pool, :doghouse]
# Appending
@house.flags << :sauna
#Querying
@house.flags.has_key? :porch
#Searching
House.where "flags LIKE ?", "pool"
1 голос
/ 10 сентября 2010

Я думаю о чем-то подобном

У вас есть домашний стол (для деталей дома)

У вас есть еще одна главная таблица под названием «Особенности» (которая имеет такие функции, как «камин», «подвал» и т. Д.)

и у вас есть объединяющий стол, как Houses_Features и у него есть house_id и feature_id

Таким образом, вы можете назначить функции для данного дома. Не знаю, соответствует ли это вашим потребностям, но подумайте об этом: D

спасибо и всего наилучшего

Sameera

0 голосов
/ 10 сентября 2010

У вас всегда может быть столбец TEXT, в котором вы держите JSON (скажем, data), и тогда ваши запросы могут использовать LIKE SQL.

Например: house.data # => '{"has_fireplace": true," has_basement ": false," has_garage ": true} '

Таким образом, выполнение поиска с использованием LIKE '%"has_fireplace":true%' вернет что-либо с камином.

Использование отношений модели (например,модель для Камина, Подвала и Гаража в дополнение к просто Хаусу в этом случае была бы чрезвычайно громоздкой, поскольку у вас так много моделей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...