Как хранить большие двоичные объекты на сервере sql
Хранение больших кусков двоичных данных в SQL Server - не лучший подход.Это делает вашу базу данных очень громоздкой для резервного копирования, а производительность, как правило, невелика.Хранение файлов обычно выполняется в системе file .Sql Server 2008 имеет встроенную поддержку FILESTREAM
.Microsoft документирует случаи использования FileStream следующим образом
- Размер хранимых объектов в среднем превышает 1 МБ.
- Важным является быстрый доступ для чтения.
- Вы разрабатываете приложения, которые используют средний уровень для логики приложения.
В вашем случае я думаю, что все пункты верны.
Включить на сервере
Чтобы включить поддержку FILESTREAM
на сервере, используйте следующую инструкцию.
EXEC sp_configure filestream_access_level, 2
RECONFIGURE
Настройка базы данных
Чтобы получитьфайловая группа filestream, связанная с вашей базой данных, создает
ALTER DATABASE ImageDB ADD FILEGROUP ImageGroup CONTAINS FILESTREAM
ALTER DATABASE ImageDB
ADD FILE ( NAME = 'ImageStream', FILENAME = 'C:\Data\Images\ImageStream.ndf')
TO FILEGROUP TodaysPhotoShoot
Создание таблицы
Следующим шагом является получение данных в базе данных с хранилищем файлового потока:
CREATE TABLE Images
(
[Id] [uniqueidentifier] ROWGUIDCOL NOT NULL PRIMARY KEY,
[CreationDate] DATETIME NOT NULL,
[ImageFile] VARBINARY(MAX) FILESTREAM NULL
)
For Filestream
для работы вам нужно не только свойство FILESTREAM
для поля в таблице, но и поле, которое имеет свойство ROWGUIDCOL
.
Вставка данных с помощью TSQL
Теперь дляДля вставки данных в эту таблицу вы можете использовать TSQL:
using(var conn = new SqlConnection(connString))
using(var cmd = new SqlCommand("INSERT INTO Images VALUES (@id, @date, cast(@image as varbinary(max))", conn))
{
cmd.Parameters.AddRange(new {
new SqlParameter("id", SqlDbType.UniqueIdentifier).Value = uId,
new SqlParameter("date", SqlDbType.DateTime).Value = creationDate,
new SqlParameter("image", SqlDbType.varbinary).Value = imageFile,
});
conn.Open
cmd.ExecuteScalar();
}
Вставка данных с использованием SqlFileStream
Существует также подход для получения данных файла на диске с использованием Win32 напрямую.Это предлагает вам потоковый доступ SqlFileStream
наследуется от IO.Stream
.
Вставка данных с использованием win32 может быть сделана, например, с помощью следующего кода:
public void InsertImage(string connString, Guid uId, DateTime creationDate, byte[] fileContent)
{
using (var conn = new SqlConnection(connString))
using (var cmd = new SqlCommand(@"INSERT INTO Images VALUES (@id, @date, cast(@image as varbinary(max)) output INSERTED.Image.PathName()" , conn))
{
conn.Open();
using (var transaction = conn.BeginTransaction())
{
cmd.Transaction = transaction;
cmd.Parameters.AddRange(
new[] {
new SqlParameter("id", SqlDbType.UniqueIdentifier).Value = uId,
new SqlParameter("date", SqlDbType.DateTime).Value = creationDate,
new SqlParameter("image", SqlDbType.VarBinary).Value = null
}
);
var path = (string)cmd.ExecuteScalar();
cmd.CommandText = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()";
var context = (byte[])cmd.ExecuteScalar();
using (var stream = new SqlFileStream(path, context, FileAccess.ReadWrite))
{
stream.Write(fileContent, 0, fileContent.Length);
}
transaction.Commit();
}
}
Как смоделировать базу данных хранилища фотографий
С помощью файлового потокахранить изображения, таблица очень узкая, что хорошо для производительности, так как многие записи могут быть сохранены на странице данных 8K.Я хотел бы использовать следующую модель:
CREATE TABLE Images
(
Id uniqueidentifier ROWGUIDCOL NOT NULL PRIMARY KEY,
ImageSet INTEGER NOT NULL
REFERENCES ImageSets,
ImageFile VARBINARY(MAX) FILESTREAM NULL
)
CREATE TABLE ImageSets
(
ImageSet INTEGER NOT NULL PRIMARY KEY,
SetName nvarchar(500) NOT NULL,
Author INTEGER NOT NULL
REFERENCES Users(USerId)
)
CREATE TABLE Users
(
UserId integer not null primary key,
UserName nvarchar(500),
AddressId integer not null
REFERENCES Addresses
)
CREATE TABLE Organsations
(
OrganisationId integer not null primary key
OrganisationName nvarchar(500),
AddressId integer not null
REFERENCES Addresses
)
CREATE TABLE Addresses
(
AddressId integer not null primary key,
Type nvarchar(10),
Street nvarchar(500),
ZipCode nvarchar(50),
City nvarchar(500),
)
CREATE TABLE OrganisationMembers
(
OrganisationId integer not null
REFERENCES Organisations,
UserId integer not null
REFERENCES Users,
PRIMARY KEY (UserId, OrganisationId)
)
CREATE NONCLUSTERED INDEX ixOrganisationMembers on OrganisationMembers(OrganisationId)
Это переводит на следующую диаграмму Entity RelationShip:
- Производительность, узкая таблица изображенийочень хорошо, так как содержит только несколько байтов данных на запись.
- Мы можем предположить, что изображение всегда является членом набора изображений. Информация о наборе может быть скрыта, если в нем всего 1 изображение.
- Я предполагаю, что вы хотите отследить, какие пользователичлен какой организации, поэтому я добавил таблицу, чтобы связать их (при условии, что пользователь может быть членом нескольких организаций).
- Первичный ключ в таблице OrganisationMembers имеет UserId в качестве первого поля, поскольку обычно там гораздо больше пользователей.чем «Организации», и вы, вероятно, захотите показать, в каких организациях пользователь является участником чаще, чем обратное.
- Индекс OrganisationId в OrganisationMembers предназначен для запросов, для которых нужен список членов для конкретной организации.быть показано.
Ссылки: