Pull to refresh

Rails и полиморфные связи

Ruby on Rails *
В большинстве руководств по Rails, которые мне попадались в руки, в примерах по полиморфным связям есть интересная особенность выбора типа для этих связей, о которой и пойдет речь в этом посте.

В Rails полиморфными считаются связи, устанавливаемые между объектами разных типов. Предполагается, что все эти объекты разделяют некоторые общие характеристики, но имеют различные качественные представления. Полиморфные связи — один из способов реализации отношения супертип-подтип.

Рассмотрим три модели:
  1. class Post < ActiveRecord::Base
  2. has_many :comments, :as => :resource
  3. end
  4. class Image < ActiveRecord::Base
  5. has_many :comments, :as => :resource
  6. end
  7. class Comment < ActiveRecord::Base
  8. belongs_to :resource, :polymorphic => true
  9. end


Такая схема требует наличие полей resource_type и resource_id для модели Comment, и в руководствах по Rails стандартно определяют resource_type как VARCHAR (255). Долгое время я не обращал на это никакого внимания, однако на днях подумал, а почему бы не сделать это поле типа Enum ('Post','Image') NOT NULL, ведь при известном количестве моделей, участвующих в полиморфной связи это не должно вызывать никаких проблем и работает быстрее.

Чтобы убедиться в выгоде использования ENUM я провел маленький опыт и сделал два приложения на Rails с указанными выше моделями. Для каждого приложения специальным скриптом сформировал два одинаковых набора данных следующим образом: сгенерировал по 1000 постов и картинок, затем 1 000 000 комментариев случайным образом так чтобы каждый создаваемый комментарий был случайно сопоставлен со случайным постом или картинкой. Этим я хотел добиться расположения комментариев вразнобой, хотя и был введен составной индекс (resource_type, resource_id).

После генерации данных провёл контрольные выборки для постов c id 100,200, …,1000 и результаты эксперимента привожу в табличке. Испытания проводились на MySQL версии 5.1.37–1ubuntu5

Таблица с результатами

Небольшое пояснение к таблице:
Т1 — таблица с resource_type VARCHAR (10) NOT NULL.
Т2 — таблица с resource_type ENUM ('Post','Image') NOT NULL.
Колонки 3 и 5 содержат время исполнения запроса вида
SELECT * FROM `comments` WHERE resource_type='Post' AND resource_id=N1;.
Колонки 4 и 6 содержат время исполнения запроса вида 
SELECT * FROM `posts` INNER JOIN comments ON `comments`.resource_type='Post' AND `comments`.resource_id=`posts`.id WHERE `posts`.id=N1.
N — номер опыта, N1=N*100.

После этого я считаю, что имеет смысл использовать ENUM поля для полиморфных связей. Но пока что мне не ясно, какие есть подводные камни? Какие есть у вас соображения насчет полиморфных связей и их использования в народном хозяйстве:)?
Tags:
Hubs:
Total votes 28: ↑20 and ↓8 +12
Views 4.9K
Comments Comments 24