Comments 36
UFO just landed and posted this here
UFO just landed and posted this here
я тоже сначала подумал о наследовании.
0
в коде наверное наследование будет неплохим вариантом, однако в структуре базы данных это будет одна таблица рейтинга — на каждую сущность.
а автор предлагает использовать одну таблицу для всех сущностей, но указывать в этой таблице тип сущности для которой делается рейтинг.
однако на месте автора я бы привел цифры по нагрузочному тестированию такого подхода к рейтингу.
возможно быстрее будет выбирать данные из разных мелких таблиц чем из одной большой.
а автор предлагает использовать одну таблицу для всех сущностей, но указывать в этой таблице тип сущности для которой делается рейтинг.
однако на месте автора я бы привел цифры по нагрузочному тестированию такого подхода к рейтингу.
возможно быстрее будет выбирать данные из разных мелких таблиц чем из одной большой.
0
Всем понятно что мой вариант будет работать медленнее, но кэширование может исправить сютуацию.
0
Неужели, полиморфные модели?
+1
труд можно СИИИИЛЬНО облегчить не плодя лишних сущностей
0
Кстати таблицу Post и Comment волне можно и соединить (в одном из внутрикорпоротивных движков блого-форума я так и сделал).
единая таблица:
Post:
id
parent_id
user_id
…
если parent_id — 0/null — то это пост/начало форума, инача коммент, ответ.
Я не говорю что это правильно и так нужно делать, просто ради прикола в одном небольшом проекте я такое забацал.
единая таблица:
Post:
id
parent_id
user_id
…
если parent_id — 0/null — то это пост/начало форума, инача коммент, ответ.
Я не говорю что это правильно и так нужно делать, просто ради прикола в одном небольшом проекте я такое забацал.
0
Информацию о рейтинге я бы однозначно закешировал в соответствующем поле у сущности. А делать выборку из таблицы Rating следовало бы только при голосовании (чтобы исключить повторные)
0
как в рельсах =)
0
Походит на ContentTypes-фреймворк в джанге. Такие связи там называются generic relations. Только там все это зашло далеко вперед, с достаточно полной поддержкой со стороны ORM. Очень широко применяется при написании подключаемых приложений.
+1
Gibbzy пишет: «Как известно в работе вёб программиста часто нужно делать что то достаточно быстро, для этого придумали множество всяческих инструментов ООП, фреймворки и много всего, но как не порождать монстров, а делать всё быстро и качественно?»
Просто знать и использовать правильные фреймворки. Хорошо разобраться в фреймворке сложнее, чем написать велосипед. Но, как мне кажется, полезнее.
И в джанге, и в рельсах (как пишет LightAlloy) это все давно реализовано и широко применяется (на рельсах не писал, но, думаю, что там тоже), с разными удобными плюшками и много-раз-наступленными граблями.
P.S. Этот конкретный велосипед считаю полезным, ход мыслей — верным.
Просто знать и использовать правильные фреймворки. Хорошо разобраться в фреймворке сложнее, чем написать велосипед. Но, как мне кажется, полезнее.
И в джанге, и в рельсах (как пишет LightAlloy) это все давно реализовано и широко применяется (на рельсах не писал, но, думаю, что там тоже), с разными удобными плюшками и много-раз-наступленными граблями.
P.S. Этот конкретный велосипед считаю полезным, ход мыслей — верным.
0
в целом решение имеет место быть, но:
1) когда сервис с высокой активностью, общая таблица будет излишне переполнена.
2) раз уж зашел разговор про Zend Framework… Не место этим методам в этом классе — мы не рейтингу рейтинг выставляем и иже с ним.
Следовательно нужены:
— абстрактный класс от которого будут наследоваться классы конкретных таблиц
— каждый класс наследующий VotingTable должен содержать определение зависимостей через $_dependentTables и реализовывать специфичный select (определение метода getTableType) в которым бы выборка производилась с учетом типа таблицы.
— Класс Rating должен содержать правила взаимосвязей с таблицами по которым ведется голосование ($_referenceMap)
— класс Voting extends Zend_Db_Table_Row_Abstract, содержащий методы работы с рейтингом с немного иной сигнатурой, которые в свою очередь будут проксировать вызов магических методов ($row->findTableClassViaIntersectionTableClassByRule1) родного механизма выборки многие ко многим [http://framework.zend.com/manual/en/zend.db.table.relationships.html#zend.db.table.relationships.fetching.many-to-many] и и создавать новые инстанции Rating (методом setRating).
Как-то так…
1) когда сервис с высокой активностью, общая таблица будет излишне переполнена.
2) раз уж зашел разговор про Zend Framework… Не место этим методам в этом классе — мы не рейтингу рейтинг выставляем и иже с ним.
Следовательно нужены:
— абстрактный класс от которого будут наследоваться классы конкретных таблиц
abstract class VotingTable extends Zend_Db_Table_Abstract { protected $_rowClass = 'Voting'; /** * @return Zend_Db_Select */ abstract function getTableType(); }
— каждый класс наследующий VotingTable должен содержать определение зависимостей через $_dependentTables и реализовывать специфичный select (определение метода getTableType) в которым бы выборка производилась с учетом типа таблицы.
— Класс Rating должен содержать правила взаимосвязей с таблицами по которым ведется голосование ($_referenceMap)
— класс Voting extends Zend_Db_Table_Row_Abstract, содержащий методы работы с рейтингом с немного иной сигнатурой, которые в свою очередь будут проксировать вызов магических методов ($row->findTableClassViaIntersectionTableClassByRule1) родного механизма выборки многие ко многим [http://framework.zend.com/manual/en/zend.db.table.relationships.html#zend.db.table.relationships.fetching.many-to-many] и и создавать новые инстанции Rating (методом setRating).
class Voting extends Zend_Db_Table_Row_Abstract { protected $_tableType; public function init() { $this->_tableType = $this->getTable()->getTableType(); } public function setRating($user, $amount) { /* ... */ } public function getRating() { /* ... */ } public function isVoted($user_id) { /* ... */ } }
Как-то так…
+1
«1) когда сервис с высокой активностью, общая таблица будет излишне переполнена.»
в чём кардинальная разница, 3 таблицы с N записями суммарно или 1 таблица с N записями?
в чём кардинальная разница, 3 таблицы с N записями суммарно или 1 таблица с N записями?
0
UFO just landed and posted this here
UFO just landed and posted this here
а вы сможете эту разницу измерить? вы уверены, что вы сейчас не экономите на списках?
озвучьте, пожалуйста, абсолютную разницу в секундах между этими 2 вариантами?
пусть, к примеру, в каждой из таблиц будет миллионов по 50 записей.
заполните и выложите результаты. потом сделайте вывод о целесообразности.
озвучьте, пожалуйста, абсолютную разницу в секундах между этими 2 вариантами?
пусть, к примеру, в каждой из таблиц будет миллионов по 50 записей.
заполните и выложите результаты. потом сделайте вывод о целесообразности.
0
Ну и ещё дополнительное условие поиска WHERE field_type=? тоже немного замедляет…
0
Прикаждом изменении таблицы придется также индексы пересчитывать — в маленькой таблице быстрее.
При большом объеме вставок будет лочиться вся таблица и больше запросов будут висеть в оидании разлока — несколько таблиц выгоднее.
любой join с бОльшей таблице будет медленнее чем с маленькой.
В общем — с точки зрения удобства программирования — здорово, с точки зрения производительности — нет, imo.
При большом объеме вставок будет лочиться вся таблица и больше запросов будут висеть в оидании разлока — несколько таблиц выгоднее.
любой join с бОльшей таблице будет медленнее чем с маленькой.
В общем — с точки зрения удобства программирования — здорово, с точки зрения производительности — нет, imo.
0
пока я пребывал в царстве морфея без меня уже все рассказали :) но дело не только в скорости, а и в объеме. простой пример: одно поле int в таблице с 50000000. а плюс к этому по нему еще *обязательно* нужно будет создавать индекс. Диски и память хоть вещь и резиновая, но все нужно расходовать с умом :)
0
если у вас проблемы с тем, что индекс не помещается в память — то не нужно этим бравировать вынужденную денормализацию в схеме и предметной области. просто возьмите FEDERATED и пусть этой работой занимается mysql.
0
у меня вообще нет проблем :)
а если по тексту:
1) slovari.yandex.ru/dict/mikhelson/article/mi11/mi1-0617.htm — как следствие «вынужденной денормализацией»
2) ru.wikipedia.org/wiki/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0. А теперь вопрос: какая именно форма нарушена разделением одной огромной таблицы на несколько помельче?
3) К вопросу об помериться скоростью выборки — предложение сделать кубического коня в вакууме, прошу прощения, и не имеет с реальной действительностью практически ничего общего. в реальности одновременно с выборкой конкретно в данную таблицу будет вестись вставка (хоть и с несколько меньшей интенсивностью), кешировать данные этой таблицы можно, но осторожно и не на долго. В контексте ORM к этой таблице будет десяток последовательных обращений. И при этом это будет делаться ну хотя бы раз 200-300 одновременно например в течении часа. наблюдения и опыт показывают, что разница может быть в пару порядков. да и почему сразу разговор про MySQL? Но если упираться в него, то есть еще как минимум шардинг.
4) ну и под конец читаем *внимательно* последнее предложение ;)
а если по тексту:
1) slovari.yandex.ru/dict/mikhelson/article/mi11/mi1-0617.htm — как следствие «вынужденной денормализацией»
2) ru.wikipedia.org/wiki/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0. А теперь вопрос: какая именно форма нарушена разделением одной огромной таблицы на несколько помельче?
3) К вопросу об помериться скоростью выборки — предложение сделать кубического коня в вакууме, прошу прощения, и не имеет с реальной действительностью практически ничего общего. в реальности одновременно с выборкой конкретно в данную таблицу будет вестись вставка (хоть и с несколько меньшей интенсивностью), кешировать данные этой таблицы можно, но осторожно и не на долго. В контексте ORM к этой таблице будет десяток последовательных обращений. И при этом это будет делаться ну хотя бы раз 200-300 одновременно например в течении часа. наблюдения и опыт показывают, что разница может быть в пару порядков. да и почему сразу разговор про MySQL? Но если упираться в него, то есть еще как минимум шардинг.
4) ну и под конец читаем *внимательно* последнее предложение ;)
0
В нескольких проектах поступал так же, при записи\удалении в таблицу рейтинга, триггер обновлял поле рейтинг для конкретной сущности (что бы НЕ суммировать рейтинг при каждой выборке сущности). Пока полет нормальный!
+1
Есть достаточно наивный вариант, чтобы не хранить информацию о типе записи в каждой таблице.
Создадим таблицу Entity (сущности), в которой будем хранить информацию о всех идентификаторах и типах. Дополнительно создадим таблицу EntityType для хранения данных о самом типе (например, имени типа 'name'). Структуру табиц буду записывать в формате: имя_таблицы: (список полей), PK(поле первичного ключа), FK (внешний ключ)
Поле EntityType.id не генерирует значения идентификатора, а ссылается на Entity.id. Т.е. тип это тоже какая-то сущность.
Аналогично — пользователи это тоже сущности.
Пользователем, который запостил статью, может быть не любая абстрактная сущность, а лишь некто из таблицы User:
Продолжим:
В таблице Comment поле item ссылается на абстрактный Entity.id. Поэтому комментировать можно любые сущности: статьи, пользователей, типы,…, какие-то другие сущности, которые появятся в будущем. Аналогично для Vote.
В приципе, на одну и ту же сущность могут ссылаться id из разных таблиц. Для хранения этих данных создадим таблицу Table, где в поле name будем хранить имя табицы. А для связи таблицы таблиц с таблицей сущностей используем отношение многие-к-многим через таблицу Entity2Table:
Таким образом для записи инфомации о новой сущности (допустим User) придется делать следующие вставки: в таблицу Entity, в таблицу User и в таблицу Entity2Table для связи вновь созданного юзера и таблицы User.
Такая структура отображается на соответствующие понятия ООП: Entity => Object, Table => Class, EntityType => DataType, Entity2Table => extends (classes).
зы: сори за сумбурность. это скорее мемори дамп.
Создадим таблицу Entity (сущности), в которой будем хранить информацию о всех идентификаторах и типах. Дополнительно создадим таблицу EntityType для хранения данных о самом типе (например, имени типа 'name'). Структуру табиц буду записывать в формате: имя_таблицы: (список полей), PK(поле первичного ключа), FK (внешний ключ)
Entity: (id:autoincrement, type:int) , PK(id), FK(type -> EntityType.id)
EntityType: (id:int, name:string), PK(id), FK(id -> Entity.id)
Поле EntityType.id не генерирует значения идентификатора, а ссылается на Entity.id. Т.е. тип это тоже какая-то сущность.
Аналогично — пользователи это тоже сущности.
User: (id:int, firstname:string)
, PK(id), FK(id -> Entity.id)
Пользователем, который запостил статью, может быть не любая абстрактная сущность, а лишь некто из таблицы User:
Article: (id:int, user:int)
, PK(id), FK(id -> Entity.id), FK(user -> User.id)
Продолжим:
Comment: (id:int, user:int, item:int)
, PK(id), FK(id -> Entity.id), FK(user -> User.id), FK(item -> Entity.id)
Vote: (id:int, user:int, item:int)
, PK(id), FK(id -> Entity.id), FK(user -> User.id), FK(item -> Entity.id)
В таблице Comment поле item ссылается на абстрактный Entity.id. Поэтому комментировать можно любые сущности: статьи, пользователей, типы,…, какие-то другие сущности, которые появятся в будущем. Аналогично для Vote.
В приципе, на одну и ту же сущность могут ссылаться id из разных таблиц. Для хранения этих данных создадим таблицу Table, где в поле name будем хранить имя табицы. А для связи таблицы таблиц с таблицей сущностей используем отношение многие-к-многим через таблицу Entity2Table:
Entity2Table: (entity:int, class:int)
, PK(entity, class), FK(entity -> Entity.id, ), FK(class -> Table.id)
Table: (int:int, name:string)
, PK(id), FK(id -> Entity.id)
Таким образом для записи инфомации о новой сущности (допустим User) придется делать следующие вставки: в таблицу Entity, в таблицу User и в таблицу Entity2Table для связи вновь созданного юзера и таблицы User.
Такая структура отображается на соответствующие понятия ООП: Entity => Object, Table => Class, EntityType => DataType, Entity2Table => extends (classes).
зы: сори за сумбурность. это скорее мемори дамп.
0
ну вот и напутал. конечно же связывать нужно не сущности с таблицами, а их типы с таблицами. т.е. Entity2Table это бред. читать:
а extends из ООП extends это EntityType2Table.
В этом случае, для в ставки юзера потребуется лишь два запроса: в Entity и в User.
EntityType2Table: (entity_type:int, table:int)
, PK(entity_type, table), FK(entity_type -> EntityType.id, ), FK(table -> Table.id)
Table: (int:int, name:string)
, PK(id), FK(id -> Entity.id)
а extends из ООП extends это EntityType2Table.
В этом случае, для в ставки юзера потребуется лишь два запроса: в Entity и в User.
0
funca, есть реляционные модели, а то что вы предложили более походит на объектную модель
а, автору да, пять, несомненное открытие америки
а, автору да, пять, несомненное открытие америки
0
И не лень же было рисовать схемки в графическом редакторе (явно не предназначенном для составления блок-схем судя по линиям и прочим деталям)
0
Sign up to leave a comment.
Сущностей много — код один