Наиболее эффективный метод для сохранения сложных типов с переменными схемами в SQL - PullRequest
4 голосов
/ 23 февраля 2011

Что я делаю

Я создаю таблицу SQL, которая обеспечит механизм внутреннего хранения для объектов сложного типа. Я пытаюсь определить, как добиться этого с лучшей производительностью. Мне нужно иметь возможность запрашивать каждое отдельное значение простого типа сложного типа (например, строковое значение City в комплексном типе Address).

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


Где я сейчас нахожусь

Сейчас я думаю создать следующие таблицы.

 TABLE:  Schemas
   COLUMN NAME       DATA TYPE
   SchemaId          uniqueidentifier
   Xsd               xml                 //contains the schema for the document of the given complex type
   DeserializeType   varchar(200)        //The Full Type name of the C# class to which the document deserializes.

 TABLE:  Documents
   COLUMN NAME       DATA TYPE      
   DocumentId        uniqueidentifier
   SchemaId          uniqueidentifier

 TABLE:  Values                            //The DocumentId+ValueXPath function as a PK
   COLUMN NAME       DATA TYPE      
   DocumentId        uniqueidentifier
   ValueXPath        varchar(250)
   Value             text

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


Что я хочу знать

Я полагаю, что есть лучшие способы выполнить то, что я пытаюсь сделать, но я немного не знаю об относительных преимуществах производительности различных методов SQL. В частности, я не знаю стоимость производительности:

1 - comparing the value of a text field versus of a varchar field.
2 - different kind of joins versus nested queries
3 - getting a view versus an xml document from the sql db
4 - doing some other things that I don't even know I don't know would be affecting my query but, I am experienced enough to know exist

Буду признателен за любую информацию или ресурсы об этих проблемах с производительностью в SQL, а также за рекомендацию о том, как подойти к этой общей проблеме более эффективно.


Например,

Вот пример того, что я сейчас планирую сделать.

У меня есть адрес класса C #, который выглядит как

public class Address{
     string Line1 {get;set;}
     string Line2 {get;set;}
     string City {get;set;}
     string State {get;set;}
     string Zip {get;set;
}

Экземпляр построен из new Address{Line1="17 Mulberry Street", Line2="Apt C", City="New York", State="NY", Zip="10001"}

его значение XML будет выглядеть следующим образом.

<Address>
   <Line1>17 Mulberry Street</Line1>
   <Line2>Apt C</Line2>
   <City>New York</City>
   <State>NY</State>
   <Zip>10001</Zip>
</Address>

Используя вышеприведенную db-схему, я бы имел одну запись в таблице Schemas с XSD-определением схемы xml адреса. Этот экземпляр будет иметь уникальный идентификатор (PK таблицы документов), который присваивается SchemaId записи адреса в таблице схем. Затем в таблице «Значения» будет пять записей, представляющих этот адрес.

Они бы выглядели так:

DocumentId                              ValueXPath        Value
82415E8A-8D95-4bb3-9E5C-AA4365850C70    /Address/Line1    17 Mulberry Street
82415E8A-8D95-4bb3-9E5C-AA4365850C70    /Address/Line2    Apt C
82415E8A-8D95-4bb3-9E5C-AA4365850C70    /Address/City     New York
82415E8A-8D95-4bb3-9E5C-AA4365850C70    /Address/State    NY
82415E8A-8D95-4bb3-9E5C-AA4365850C70    /Address/Zip      10001

Только что добавили награду ...

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

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

Ответы [ 5 ]

3 голосов
/ 11 марта 2011

Как насчет поиска решения на архитектурном уровне?Я также ломал голову над сложными графиками и производительностью, пока не обнаружил CQRS .

[режим запуска евангелиста]

  • Вы можете перейти на документную или реляционнуюв качестве хранилища.Даже оба!(Event Sourcing)
  • Хорошее разделение задач: Читай Модель против Напиши Модель
  • Имей свой торт и ешь его тоже!

Хорошо, начальное обучение/ техническая кривая, чтобы преодолеть;)

[конец режима евангелиста]

Как вы заявили: " Мне нужно иметь возможность создавать переменные схемы на лету, ничего не изменяя вслой доступа к базе данных."Ключевое преимущество заключается в том, что ваша модель чтения может быть очень быстрой, поскольку она предназначена для чтения.Если вы добавите Event Sourcing к миксу, вы можете сбросить и перестроить вашу модель чтения в соответствии с любой схемой, которую вы хотите ... даже «онлайн».

Существует несколько хороших платформ с открытым исходным кодом, таких как nServiceBus, которые экономят много времени и технических проблем.Все зависит от того, насколько далеко вы хотите принять эти концепции, на что вы готовы / можете потратить время.Вы даже можете начать с основ, если будете следовать подходу Грега Янга.См. Информацию в ссылках ниже.

См.

2 голосов
/ 23 февраля 2011

Каким-то образом то, что вы хотите, звучит как болезненная вещь в SQL. По сути, вы должны рассматривать внутреннюю часть текстового поля как непрозрачную, как при запросе базы данных SQL. Текстовые поля не были созданы для эффективных запросов.

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

Ваша идея звучит так, как будто вы хотите выполнить несколько объединений, анализ XML и приложение XPath, чтобы получить значение. Это не кажется мне самой эффективной вещью.

Итак, мой совет:

  • Либо просто храните сериализованные объекты в БД, и ничего не делайте, только загружайте их и выполняйте все другие операции в памяти
  • Или, если вам нужно выполнить запрос к сложным структурам данных, вы действительно можете посмотреть на хранилища / базы данных документов, такие как CouchDB или MongoDB ; Вы также можете проверить Википедию по теме . Есть даже базы данных, специально предназначенные для хранения XML , хотя мне лично они не очень нравятся.

Приложение, согласно вашим объяснениям выше

Проще говоря, не переусердствуйте с этой вещью:

  • Если вы просто хотите сохранить объекты C # / .NET, просто используйте XML-сериализацию , уже встроенную в фреймворк , в одну таблицу и покончите с этим.
  • Если вам по какой-то причине необходимо хранить сложный XML, используйте выделенное хранилище XML
  • Если у вас есть фиксированная схема базы данных, но она слишком сложна для эффективных запросов, используйте хранилище документов в памяти, где вы храните денормализованную версию ваших данных для более быстрых запросов (или просто упростите схему базы данных)
  • Если вам на самом деле не нужна фиксированная схема, используйте только хранилище документов и забудьте о наличии какого-либо «определения схемы»

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

Если вы хотите проверить базы данных документов, есть драйверы .NET для CouchDB и MongoDB . База данных eXist XML предлагает несколько веб-протоколов, и вы, вероятно, можете легко создать класс клиента с помощью интерфейса VisualStudio «наведи и снимай». Или просто Google для кого-то, кто уже сделал.

1 голос
/ 10 марта 2011

Мне нужно иметь возможность создавать переменные схемы на лету без изменения что-нибудь о доступе к базе данных слой. * * +1002

Вы повторно внедряете СУБД в СУБД. БД уже может это сделать - вот для чего нужны операторы DDL, такие как create table и create schema ....

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

Edit: Немного более длинный ответ, если у вас нет полных требований сразу, я бы сохранил данные как тип данных XML и запросил бы их, используя запросы XPath. Это будет нормально для случайных запросов по небольшому количеству строк (конечно, менее нескольких тысяч).

Кроме того, ваша СУБД может поддерживать индексы поверх XML, что может быть еще одним способом решения вашей проблемы. CREATE XML INDEX в SqlServer 2008, например.

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

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

Я предполагаю, что я говорю: «Вы уверены, что вам нужно сделать это, а XML не может просто делать свою работу».

0 голосов
/ 09 марта 2011

Интересный вопрос.

Я думаю, что вы, возможно, задаете не тот вопрос здесь.Вообще говоря, если у вас есть текст FULLTEXT в вашем текстовом поле, запросы будут выполняться быстро.Например, намного быстрее, чем varchar, если вам нужно использовать подстановочные знаки.

Однако на вашем месте я бы сконцентрировался на реальных запросах, которые вы собираетесь выполнять.Вам нужны логические операторы?Wildcards?Числовые сравнения?Вот где, я думаю, вы столкнетесь с реальными проблемами производительности.

Я бы подумал, что вам понадобятся запросы типа:

  • ", найдите все адреса в штатах Нью-Йорк, Нью-Джерси иПенсильвания "
  • " найти все адреса между номерами домов 1 и 100 на Малберри-стрит "
  • " найти все адреса, где отсутствует почтовый индекс, а город - Нью-Йорк "

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

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

Некоторые уточнения, которые я бы порекомендовал, это посмотреть на модель предметной области и, по крайней мере, посмотреть, сможете ли вы выделить отдельные типы данных в столбец «значение»;вы можете получить «textValue», «moneyValue», «integerValue» и «dateValue».В приведенном вами примере вы можете указать «address 1» в «housenumber» (как целое число) и «streetname».

Сказав все это, я не думаю, что есть лучшее решение, чем полностьюпереход на базу данных, ориентированную на документы.

0 голосов
/ 23 февраля 2011

Частично это будет зависеть от вашего движка БД. Вы используете SQL Server, не так ли?

Отвечая на ваши темы:

1 - Сравнение значения текстового поля с полем varchar: если вы сравниваете два поля БД, поля varchar умнее. Nvarchar (max) хранит данные в юникоде с 2 * 1 + 2 байтами, где "l" - длина. Что касается проблем с производительностью, вам нужно будет подумать, насколько большими будут таблицы, чтобы выбрать лучший способ индексировать (или нет) поля таблицы. см. Тему .

2 - Иногда вложенные запросы легко создаются и выполняются, что также помогает сократить время запроса. Но, в зависимости от сложности, было бы лучше использовать различные виды соединений. Лучший способ - попытаться сделать это обоими способами. Выполняйте два или более раз каждый запрос, потому что механизм БД «компилирует» запрос при первом выполнении, затем последующие выполняются довольно быстро. Измерьте время для разных параметров и выберите лучший вариант.

"Иногда вы можете переписать подзапрос, чтобы использовать JOIN и добиться большей производительности. Преимущество создания JOIN состоит в том, что вы можете оценивать таблицы в порядке, отличном от того, который определен в запросе. Преимущество использования подзапроса состоит в том, что он Часто нет необходимости сканировать все строки из подзапроса, чтобы оценить выражение подзапроса. Например, подзапрос EXISTS может возвращать TRUE при просмотре первой подходящей строки. " - ссылка

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

4- Другие проблемы касаются общего количества записей, ожидаемых для вашей таблицы; индексирование столбцов, в котором вам нужно рассмотреть сортировку, объединение, фильтрацию, PK и FK. Каждая ситуация может потребовать разных подходов. Мое предложение состоит в том, чтобы потратить некоторое время на чтение о вашем ядре базы данных и функционировании запросов, относящихся к вашей системе.

Надеюсь, я помог.

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