2010-01-10 6 views
18

У меня есть проект, который требует определенных пользователем атрибутов для определенного объекта во время выполнения (скажем, объект-человек в этом примере). В проекте будет много разных пользователей (1000 +), каждый из которых определяет свои собственные уникальные атрибуты для собственных наборов объектов Person.Еще один вопрос о динамической модели данных

(Например, пользователь # 1 будет иметь набор определенных атрибутов, который будет применяться ко всем принадлежащим ему объектам пользователя. Мать это будет 1000 пользователей, и это минимальное количество пользователей, которое приложение будет работать с.) Эти атрибуты будут использоваться для запроса объекта people и возврата результатов.

Я думаю, что это возможные подходы, которые я могу использовать. Я буду использовать C# (и любую версию .NET 3.5 или 4), и у вас есть свободное владение re: что использовать для хранилища данных. (У меня есть mysql и mssql, хотя у вас есть свобода использовать любое программное обеспечение, если оно будет соответствовать счету)

Пропустил ли я что-нибудь или сделал какие-либо неправильные предположения в своей оценке?

Из этих вариантов - какое решение вы бы выбрали?

  1. Гибридная модель объекта EAV. (Определите базу данных с использованием обычной реляционной модели и найдите таблицу «Property Bag» для таблицы Person).

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

    Я постучал быстрый образец, который имеет дозвуковой 2.x «esqe интерфейс:

    Select().From().Where ... etc 
    

    , который генерирует правильное соединение, то фильтры + вращают возвращаемые данные в C#, чтобы возвращать datatable, настроенный с правильно введенным набором данных.

    Мне еще нужно загрузить это тестовое решение. Он основан на совете EA в этом техническом документе Microsoft: SQL Server 2008 RTM Documents Best Practices for Semantic Data Modeling for Performance and Scalability

  2. Позволяет пользователю динамически создавать/изменять таблицу объекта во время выполнения. Это решение я считаю, NHibernate делает в фоновом режиме при использовании динамических свойств, как описано, где

    http://bartreyserhove.blogspot.com/2008/02/dynamic-domain-mode-using-nhibernate.html

    Downsides:

    По мере роста системы, количество столбцов, определенных будет очень большим, и может поражать максимальное количество столбцов. Если есть 1000 пользователей, каждый из которых имеет 10 различных атрибутов для своих объектов Person, тогда нам понадобится таблица, содержащая 10k столбцов. Не масштабируется в этом сценарии.

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

    Я не уверен, что это будет масштабируемо, но это не похоже. Кто-то, пожалуйста, поправьте меня, если я ошибаюсь!

  3. Используйте хранилищу NoSQL, такие как CouchDB/MongoDb

    Из того, что я читал, это еще не доказано в крупномасштабных приложений, основанный на строках, и очень рано в стадии разработки.ЕСЛИ я ошибаюсь в этой оценке, может ли кто-нибудь сообщить мне об этом?

    http://www.eflorenzano.com/blog/post/why-couchdb-sucks/

  4. Использование столбца XML в таблице людей в магазине Атрибуты

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

  5. Сериализация графического объекта в базу данных.

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

  6. C# привязок для berkelyDB

    Из того, что я прочитал здесь: http://www.dinosaurtech.com/2009/berkeley-db-c-bindings/

    Berkeley Db определенно доказано, чтобы быть полезным, но, как Роберт отметил, - там нет простого интерфейса. Вся ваша обертка WOO должна быть закодирована вручную, а все ваши индексы поддерживаются вручную. Это намного сложнее, чем SQL/linq-to-sql, но это цена, которую вы платите за нелепую скорость.

    Кажется, что большие накладные расходы - однако, если кто-либо может предоставить ссылку на учебник о том, как поддерживать индексы на C#, это может быть искатель.

  7. [EDIT - только что добавил этот] гибрид SQL/RDF. Странно, я не думал об этом раньше. Как и в случае с вариантом 1, но вместо таблицы «property bag», только XREF в хранилище RDF? . Запрос будет включать в себя два шага - запрос в хранилище RDF для людей, попадающих в правильные атрибуты, для возврата объекта (-ов) человека и использования идентификаторов для этого объекта-человека в запросе SQL для возврата реляционных данных. Дополнительные накладные расходы, но могут быть искателями.

Я очень благодарен за любые вводные данные здесь!

+1

+1 за хорошие исследования, прежде чем задать вопрос. Посмотрите на MongoDB. Попробуйте прослушать [this] (http://www.dotnetrocks.com/default.aspx?showNum=507) подкаст и, похоже, это то, что вы ищете. Извините, я не использовал его лично. – shahkalpesh

+0

Для информации по 4; вы можете комбинировать столбцы xml с вычисленными столбцами + persisted + indexed, но вы вернетесь в сценарий «слишком много столбцов». Вам нужно уметь ** искать ** по динамическим свойствам? Это может быть кодовым фактором, который различает мешок свойств через пары ключ/значение в таблице и сериализацию/xml. –

+0

Да - основной задачей приложения является поиск по динамическим свойствам эффективным способом. Я не думал о объединении столбцов xml с вычисленными столбцами + persisted + indexed - есть ли у вас какие-либо ресурсы, объясняющие это дальше? – James

ответ

7

Механизм базы данных ESENT в Windows используется для такого рода полуструктурированных данных. Одним из примеров является Microsoft Exchange, который, как и ваше приложение, имеет тысячи пользователей, каждый из которых может определить свой собственный набор свойств (MAPI named properties). Exchange использует слегка измененную версию ESENT.

ESENT обладает множеством функций, которые позволяют приложениям с большими требованиями к метаданным: каждая таблица ESENT может иметь около ~ 32 тыс. Столбцов; таблицы, индексы и столбцы могут быть добавлены во время выполнения; разреженные столбцы не занимают места записи, если не установлены; и таблицы шаблонов могут уменьшить пространство, используемое самими метаданными. Для крупных приложений обычно имеется тысячи таблиц/индексов.

В этом случае вы можете иметь одну таблицу для каждого пользователя и создавать столбцы для каждого пользователя в таблице, создавая индексы для любых столбцов, которые вы хотите запросить. Это будет похоже на то, как некоторые версии Exchange хранят свои данные. Недостатком этого подхода является то, что у ESENT нет механизма запросов, поэтому вам придется обрабатывать ваши запросы в виде вызовов MakeKey/Seek/MoveNext.

Управляемая оболочка для ESENT здесь:

http://managedesent.codeplex.com/

+0

Ничего себе! Да, я, конечно, пропустил это в своих исследованиях. Кажется, это хорошо, чтобы быть правдой. Интересно, есть ли кто-нибудь, кто использует это для запуска веб-приложения (кроме обмена) ... Hmnnn ... – James

+1

Прошу прощения за поздний прием - esent выигрывает руки, даже с немного подробным запросом api! – James

0

Рекомендация:

Разрешить печать объектов как индексируемых. Имейте небольшое ограничение по числу индексируемых свойств и по столбцам на объект. Имейте большой жесткий предел для всех типов столбцов во всех объектах.

Реализовать индексы как отдельные таблицы (по одному на индекс), соединенные с основной таблицей данных (основная таблица имеет большой уникальный ключ для объекта). (Тогда таблицы индексов могут быть созданы/удалены).

Сериализуйте данные, включая столбцы индексов, плюс добавьте правильные значения индекса в реляционные столбцы первого класса в их выделенные индексные таблицы. Используйте JSON вместо XML для экономии места в таблице. Принудительная политика имени столбца (или длинное отображаемое имя и краткая политика имен) позволяет сэкономить место и увеличить производительность.

Используйте кварки для идентификаторов полей (но только в главном двигателе, чтобы сэкономить RAM и ускорить некоторые операции чтения - во всех случаях не полагайтесь на сравнение указателей кварков).

Моя мысль о ваших вариантах:

1 является возможной.Очевидно, что производительность будет ниже, чем если не будут сохранены столбцы идентификаторов полей.

2 не является общим драйвером для БД, не все довольны динамическими изменениями схемы. Но возможно, да, если ваш двигатель БД хорош в этом.

3 Возможно.

4 Да, хотя я бы использовал JSON.

5 Похоже, что 4 менее оптимизирован ??

6 Звучит неплохо; будет идти, если с удовольствием попробует что-то новое, а также если вы будете довольны надежностью и производительностью, но, как правило, захотите пойти с более распространенными технологиями. Я также хотел бы уменьшить количество движков, участвующих в координации транзакции, чтобы быть меньше, чем здесь.

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

Редактировать: Изменено последнее изменение формулировки.

+0

Привет, Мартин, спасибо! Отличные моменты, особенно заново: # 6 и количество двигателей ... Я не уверен в 2 предметах - не могли бы вы рассказать подробнее? re: 1: «Производительность явно ниже, чем если бы поля« Идентификаторы полей »не были сохранены». Я не понимаю, что вы имеете в виду - не могли бы вы расширить? re: «Внедрить индексы в виде отдельных таблиц». Если я правильно понимаю, значит ли это, что для каждого из 1000 «пользователей» системы, скажем, что они будут иметь/использовать 10 индексируемых столбцов каждый, это будет означать, что в базе данных будет 10k «индексных» таблиц ? Или я совершенно неправильно понял? – James

+0

RE: # 1 Я предполагаю, что в сумке для владения сайтом будут столбцы KEY & VALUE. Все, что я говорю в своем комментарии к 1, это, вероятно, лучше не хранить КЛЮЧ. RE: «10k индексных таблиц?» Я не уверен, что я верю, что у вас будет 10 тысяч уникальных свойств для человека! (больше, чем 2000 вершин), но теоретически, если у вас действительно есть большое количество таблиц, вы можете иметь N стандартных числовых индексов, доступных стандартных индексов строк, а пользователь сопоставляет свои свойства с ними, а вы разбиваете индексы немного среди пользователей Население. Я уступаю постоянным изменениям схемы на столах 10k, звучит немного. – martinr

+0

Я имею в виду, что «лучше не хранить KEY» использовать другое решение (не мешок с недвижимостью), в котором у вас нет поля SQL KEY. – martinr

0

Предполагая вам место лимита N, о том, сколько пользовательских атрибутов может определить каждый пользователь; просто добавьте N дополнительных столбцов в таблицу Person. Затем укажите отдельную таблицу, в которой вы храните метаданные для каждого пользователя, чтобы описать, как интерпретировать содержимое этих столбцов для каждого пользователя. Подобно # 1, как только вы читаете данные, но нет соединений, необходимых для привлечения пользовательских атрибутов.

+0

Звучит неплохо - но не ограничивает ли это объекты «единичными атрибутами»? Если бы я хотел сохранить, скажем, коллекцию из десяти лучших книг для человека, в гибридной модели EAV, я мог бы установить несколько атрибутов «favourite_book» и запросить вроде: «WHERE pp1.PropertyName =« favourite_book »и pp1.PropertyValue = 'catch22' AND pp2.PropertyName = 'favourite_book' и pp2.PropertyValue = 'bible' "Если мне нужно установить ограничение на количество настраиваемых атрибутов (используйте столбцы таблицы), я бы не смог сохранить эти данные. (Я мог бы, но не столкнулся с колонками, и запросы были бы сложны для генерации динамически). – James

2

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

Например, запрос может возвращать людей с расширенной собственности 'Возраст'> 18:

Свойства таблицы:

1  Age 
2  NickName 

Первый ResultSet:

PersonID Name 
1  John 
2  Mary 

второй ResultSet:

PersonID PropertyID Value 
1  1   24 
1  2   'Neo' 
2  1   32 
2  2   'Pocahontas' 

Для первого результирующего необходимо внутреннее соединения для «возраста» продлили свойство для запроса основной объекта Person сущности части:

select p.ID, p.Name from Persons p 
join PersonExtendedProperties pp 
on p.ID = pp.PersonID 
where pp.PropertyName = 'Age' 
and pp.PropertyValue > 18 -- probably need to convert to integer here 

Для второго результирующем мы делаем внешнее соединение первых результирующий с таблицей PersonExtendedProperties, чтобы получить остальные расширенные свойства. Это «узкий» набор результатов, мы не сворачиваем свойства в sql, поэтому здесь нам не нужны несколько соединений.

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

+0

очень интересно ... Какие RDMS вы используете в качестве бэкэнд? Я сейчас (время, позволяя -и, в выходные), чтобы изменить мой первоначальный тест (вариант 1), чтобы отразить этот метод (только присоединиться к каждому атрибуту запроса) и повернуть таблицу с содержимым внешнего интерфейса (с некоторой фильтрацией и т.д). Я требую этого окончательного стержня, поэтому я могу подключить любые результаты запроса EAV во все, что принимает данные ... Hmmnnn ... Если бы у меня было больше времени. Мое чувство кишки этот метод будет превосходить оригинальный метод (из-за меньшего количества присоединяется), если мы имеем дело с релятивистскими небольшими наборами атрибутов/данных. – James

+0

MSSQLServer. Сам запрос (без подачи набора результатов) фактически превосходит некоторые собственные таблицы в моих тестах. (4 параметра, участвующих в фильтрации из 20 доступных). Возможно, это связано с логистикой «широких» табличных индексов на диске. –

0

Для задачи, подобной вашей проблемы, мы использовали «XML-столбец» подход (четвертый в своем обзоре методов). Но вы должны заметить, что многие базы данных (DBMS) поддерживают индекс для значений xml.

Я рекомендую вам использовать одну таблицу для Лица, которая содержит один столбец xml вместе с другими общими столбцами. Другими словами, создайте таблицу Person с столбцами, которые являются общими для всех записей человека, и добавьте один столбец xml для динамических и разных атрибутов.

Мы используем Oracle. он поддерживает индекс для своего xml-типа. Поддерживаются два типа индексов: 1- XMLIndex для индексирования элементов и атрибутов в xml, 2- текстовом индексе Oracle для включения полнотекстового поиска в текстовых полях xml.

Например, в Oracle вы можете создать индекс, такие как:

CREATE INDEX index1 ON table_name (XMLCast(XMLQuery ('$p/PurchaseOrder/Reference' 
    PASSING XML_Column AS "p" RETURNING CONTENT) AS VARCHAR2(128))); 

и XML-запросов поддерживается только в некоторых запросах:

SELECT count(*) FROM purchaseorder 
    WHERE XMLCast(XMLQuery('$p/PurchaseOrder/Reference' 
    PASSING OBJECT_VALUE AS "p" RETURNING CONTENT) 
    AS INTEGER) = 25; 

Как я знаю, другие базы данных, такие как PostgreSQL и MS SQL Server (но не mysql) поддерживают такие индексные модели для значения xml.

Смотри также: http://docs.oracle.com/cd/E11882_01/appdev.112/e23094/xdb_indexing.htm#CHDEADIH

Смежные вопросы