Хотя я не согласен с тем, что большие двоичные объекты должны просто находиться в другой таблице - их вообще не должно быть в базе данных . Сохраните указатель на то, где файл находится на диске, а затем просто получите это из базы данных ...
Основная проблема, которую они вызывают (для меня), связана с индексацией. Используя XML с планами запросов, потому что у всех есть их, давайте сделаем таблицу:
SELECT TOP 1000
ID = IDENTITY(INT,1,1),
deq.query_plan
INTO dbo.index_test
FROM sys.dm_exec_cached_plans AS dec
CROSS APPLY sys.dm_exec_query_plan(dec.plan_handle) AS deq
ALTER TABLE dbo.index_test ADD CONSTRAINT pk_id PRIMARY KEY CLUSTERED (ID)
Это всего 1000 строк, но проверка по размеру ...
sp_BlitzIndex @DatabaseName = 'StackOverflow', @SchemaName = 'dbo', @TableName = 'index_test'
Это более 40 МБ только для 1000 строк. Предполагая, что вы добавляете 40 МБ каждые 1000 строк, это может стать довольно уродливым довольно быстро. Что происходит, когда вы попали в миллион строк? Это примерно 1 ТБ данных.
Любые запросы, которым необходимо использовать ваш кластеризованный индекс, теперь должны считывать все эти BLOB-данные в память для уточнения: при обращении к столбцу BLOB-данных.
Можете ли вы придумать лучшие способы использования памяти SQL Server, чем хранение больших двоичных объектов? Потому что я уверен, что могу.
Расширяя его до некластеризованных индексов:
CREATE INDEX ix_noblob ON dbo.index_test (ID)
CREATE INDEX ix_returnoftheblob ON dbo.index_test (ID) INCLUDE (query_plan)
Вы можете спроектировать свои некластеризованные индексы так, чтобы они в значительной степени избегали столбца BLOB, чтобы обычные запросы могли избегать кластеризованного индекса, но как только вам понадобится этот столбец BLOB, вам потребуется кластеризованный индекс.
Если вы добавите его как INCLUDED
столбец в некластеризованный индекс, чтобы избежать сценария поиска ключа, вы получите гигантские некластеризованные индексы:
Больше проблем они вызывают:
- Если кто-то запускает
SELECT *
запрос, он получает все эти данные BLOB.
- Они занимают место в резервных копиях и восстанавливают, замедляя их
- Они замедляются
DBCC CHECKDB
, потому что я знаю, что вы проверяете на коррупцию, верно?
- И если вы выполняете какие-либо операции с индексами, они также замедляют это.
Надеюсь это поможет!
Насколько велики эти изображения и сколько вы ожидаете иметь? Хотя я в основном согласен с @sp_BlitzErik , я думаю, что есть некоторые сценарии, в которых это можно сделать, и поэтому было бы полезно получить более четкое представление о том, что на самом деле запрашивается здесь.
Вот некоторые варианты, которые следует учитывать, чтобы смягчить большинство негативных аспектов, указанных Эриком:
Обе эти опции предназначены для того, чтобы быть средним звеном между хранением больших двоичных объектов либо полностью в SQL Server, либо полностью снаружи (за исключением строкового столбца для сохранения пути). Они позволяют BLOB-объектам быть частью модели данных и участвовать в транзакциях, не тратя пространство в пуле буферов (то есть в памяти). Данные BLOB по-прежнему включены в резервные копии, что делает их занимающими больше места и занимающими больше времени для резервного копирования ичтобы восстановить. Тем не менее, я с трудом воспринимаю это как настоящий минус, учитывая, что если оно является частью приложения, то необходимо каким-то образом выполнить резервное копирование, а наличие только строкового столбца, содержащего путь, полностью отключается и позволяет файлам BLOB получить удаляется без указания на это в БД (т.е. неверные указатели / отсутствующие файлы). Это также позволяет «удалять» файлы внутри БД, но они все еще существуют в файловой системе, которую в конечном итоге необходимо будет очистить (например, от головной боли). Но если файлы ОГРОМНЫЕ, то, возможно, лучше оставить полностью вне SQL Server, за исключением столбца пути.
Это помогает с вопросом «внутри или снаружи», но не затрагивает вопрос «одна таблица против нескольких таблиц». Могу сказать, что помимо этого конкретного вопроса, безусловно, существуют веские случаи для разделения таблиц на группы столбцов на основе шаблонов использования. Часто, когда у одного есть 50 или более столбцов, есть те, к которым часто обращаются, а некоторые нет. Некоторые столбцы часто пишутся, а некоторые в основном читаются. Разделение часто обращающихся и редко используемых столбцов на несколько таблиц, имеющих отношение 1: 1, довольно часто полезно, потому что зачем тратить пространство в пуле буферов для данных, которые вы, вероятно, не используете (аналогично тому, как хранить большие изображения в обычном режиме).
VARBINARY(MAX)
столбцы это проблема)? Вы также повышаете производительность часто используемых столбцов, уменьшая размер строки и, следовательно, размещая больше строк на странице данных, делая чтение (как физическое, так и логическое) более эффективным. Конечно, вы также вносите некоторую неэффективность, когда вам нужно дублировать PK, и теперь иногда вам нужно объединить две таблицы, что также усложняет (хотя и незначительно) некоторые запросы.Итак, есть несколько подходов, которые вы можете использовать, и что лучше всего зависит от вашей среды и того, что вы пытаетесь достичь.
Не все так просто. Вы можете найти некоторую полезную информацию здесь, каков размер указателя большого объекта для (MAX) типов, таких как Varchar, Varbinary, Etc? , но основы таковы:
TEXT
,NTEXT
иIMAGE
типы данных (по умолчанию): 16-байтовый указательVARCHAR(MAX)
,NVARCHAR(MAX)
,VARBINARY(MAX)
(По умолчанию):источник
Если по какой-либо причине данные должны храниться в SQL Server, я могу подумать о нескольких преимуществах их хранения в отдельной таблице. Некоторые из них более убедительны, чем другие.
Помещение данных в отдельную таблицу означает, что вы можете хранить их в отдельной базе данных. Это может иметь преимущества для планового технического обслуживания. Например, вы можете работать
DBCC CHECKDB
только в той базе данных, которая содержит данные BLOB.Если вы не всегда помещаете более 8000 байтов в BLOB, возможно, он будет храниться в строке для некоторых строк. Вы можете не захотеть этого, потому что это замедлит запросы, которые обращаются к данным, используя кластеризованный индекс, даже если столбец не нужен для запроса. Помещение данных в отдельную таблицу устраняет этот риск.
При хранении вне строки SQL Server использует указатель длиной до 24 байтов, чтобы указывать на новую страницу. Это занимает место и ограничивает общее количество столбцов BLOB, которые вы можете добавить в одну таблицу. Смотрите ответ srutzky для более подробной информации.
Кластерный индекс columnstore не может быть определен для таблицы, содержащей столбец BLOB. Это ограничение было снято и будет удалено в SQL Server 2017.
Если вы в конечном итоге решите, что данные должны быть перемещены за пределы SQL Server, это может быть проще сделать это изменение, если данные уже находятся в отдельной таблице.
источник