Структурирование таблицы базы данных с большим текстовым полем

#sql-server

#sql-сервер

Вопрос:

Я ищу совет по структурированию таблицы данных, как в заголовке, чтобы сделать ее эффективной для запросов и записи. Я храню информацию о сущности, которая имеет обычные типы данных, числа, короткую строку и т. Д. Теперь мне нужно сохранить дополнительное поле с большим объемом данных (~ 30 КБ), и я рассматриваю два варианта:

  1. добавьте столбец an nvarchar(100000) в таблицу сущностей
  2. создайте отдельную таблицу для хранения таких данных и ссылки из таблицы сущностей

другие факторы:

  • каждая строка объекта будет иметь сопутствующее большое текстовое поле
  • каждое сопровождающее текстовое поле будет содержать не менее 20 КБ данных
  • ~ 20% запросов к таблице сущностей также нуждаются в большом поле. Другие запросы могут обойтись без этого
  • ~ 95% запросов ищут одну сущность
  • Я использую O / RM для доступа к данным, поэтому все столбцы извлекаются (я мог бы выбирать и выбирать, делая код ужасным)

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

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

Комментарии:

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

2. Я хотел бы предложить прочитать о полнотекстовом поиске и поле ntext.

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

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

Ответ №1:

Недавно у нас была именно эта проблема. (хотя это был столбец XML вместо NVarchar(max)), но проблема точно такая же.

Наш вариант использования заключался в отображении списка записей на веб-странице (первые 6 столбцов) таблицы, а затем в хранении тонны дополнительной информации в столбце nvarchar (max), который отображался после выбора отдельной строки.

Первоначально одна таблица содержала все 7 столбцов.

 TABLE 1
    INT ID (PK IDentity)
    5 other columns
    NVARCHAR(max)
  

Как только мы изменили ее на следующую, мы получили огромное повышение производительности.

 TABLE 1
    INT ID (PK IDentity)
    5 other columns
    INT FID  (FK -TABLE2)

TABLE 2
    FID (PK IDENTITY)
    nvarchar(max)
  

Причина в том, что если она nvarchar(max) достаточно короткая, она будет сохранена «в строке», но если она выходит за рамки размера страницы, то она сохраняется в другом месте, и в зависимости от а) размера таблицы и набора записей, которые вы запрашиваете, и б) объема данных в вашем nvarchar(max) thisможет иметь довольно резкое падение производительности.

Прочтите эту ссылку: http://msdn.microsoft.com/en-us/library/ms189087.aspx

Когда в строке данных хранится значение большого типа значения или значение столбца типа данных большого объекта, компоненту Database Engine не нужно обращаться к отдельной странице или набору страниц для чтения или записи символа или двоичной строки. Это делает чтение и запись строк в строке примерно такими же быстрыми, как чтение или запись строк varchar, nvarchar или varbinary ограниченного размера. Аналогично, когда значения хранятся вне строки, компонент Database Engine выполняет дополнительное чтение или запись страницы.

Я бы сейчас стиснул зубы и спроектировал ваши таблицы так, чтобы хранить большие nvarchar(max) данные в отдельной таблице, предполагая, что вам не нужны данные, которые она содержит в каждом select запросе

С уважением, ваш комментарий об использовании ORM. в нашей ситуации мы также использовали NHibernate. Относительно легко настроить ваши сопоставления для отложенной загрузки связанного объекта по требованию.

Комментарии:

1. Спасибо! Это побудило меня создать отдельную таблицу. Мне нужно хранить большой XML, но у меня также есть еще один столбец, который является JSON, поэтому я постарался сделать свой вопрос более общим и не спрашивать о xml типе SQL. Еще раз спасибо.

2. нет проблем. Буквально разместил этот переработанный код в Proudction за последние 2 дня. 🙂

Ответ №2:

Ну, вы могли бы начать с документации…

добавьте столбец nvarchar(100000) в таблицу сущностей

Учитывая документированный максимальный размер поля в 8000 байт и, следовательно, nvarchar (4000) является максимальным, мне интересно узнать, как вы рассматриваете этот вариант?

nvarchar(max) — ntext и т.д. было бы правильно поступить.

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

Комментарии:

1. Спасибо, что указали мне на ограничение размера. Я просмотрел документацию, но увидел только то, что хотел увидеть («максимальный размер хранилища составляет 2 ^ 31-1 байт», но теперь, когда вы указали мне назад, я вижу, что это для nvarchar(max) ). Как вы видите, я знаю об ограничениях ORM и готов их обойти. Я не планирую извлекать мегабайты данных за запрос.

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

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

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