динамическая модель данных - PullRequest
18 голосов
/ 10 января 2010

У меня есть проект, который требует определенных пользователем атрибутов для конкретного объекта во время выполнения (скажем, объект person в этом примере). В проекте будет много разных пользователей (1000+), каждый из которых будет определять свои уникальные атрибуты для своих собственных наборов объектов «Персона».

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

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

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

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

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

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

    Я набрал быстрый образец, который имеет интерфейс Subsonic 2.x 'esqe:

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

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

    Мне еще предстоит загрузить это решение. Он основан на советах EA в этом техническом документе Microsoft: Документы по SQL Server 2008 RTM. Рекомендации по моделированию семантических данных для повышения производительности и масштабируемости

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

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

    Downsides:

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

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

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

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

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

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

  4. Использование столбца XML в таблице people для хранения атрибутов

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

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

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

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

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

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

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

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

Ответы [ 5 ]

7 голосов
/ 28 января 2010

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

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

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

Управляемый упаковщик для ESENT находится здесь:

http://managedesent.codeplex.com/

2 голосов
/ 11 января 2010

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

Например, запрос может вернуть лиц с расширенным свойством 'Age'> 18:

Таблица свойств:

1        Age
2        NickName

Первый набор результатов:

PersonID Name
1        John
2        Mary

второй результат:

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

Для первого набора результатов вам нужно внутреннее объединение для расширенного свойства 'age' для запроса базовой части сущности объекта 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 голосов
/ 26 июня 2013

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

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

Мы используем Oracle. он поддерживает индекс для своего xml-типа. Поддерживаются два типа индексов: 1- XMLIndex для индексирования элементов и атрибутов в XML, 2 - Oracle Text Index для включения полнотекстового поиска в текстовых полях 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

0 голосов
/ 11 января 2010

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

0 голосов
/ 10 января 2010

Моя рекомендация:

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

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

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

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

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

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

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

3 Возможно.

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

5 Похоже, только 4 менее оптимизированы ??

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

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

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

...