Ответ 1
Как хранить большие капли в sql-сервере
Хранение больших кусков двоичных данных в SQL Server - отличный подход. Это делает вашу базу данных очень громоздкой для резервного копирования и производительность, как правило, невелика. Хранение файлов обычно выполняется в системе . 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
)
Для 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)
Это означает следующую диаграмму привязки сущностей:
- Производительность мудрая, таблица узких изображений очень хороша, так как содержит только несколько байтов данных на запись.
- Мы можем предположить, что изображение всегда является частью набора изображений. Информация Set может быть скрыта, если в нем есть только 1 изображение.
- Я предполагаю, что вы хотите отслеживать, какие пользователи являются членами каких-либо организаций, поэтому я добавил таблицу для их ссылки (предполагая, что пользователь может быть членом нескольких организаций).
- Первичный ключ в таблице OrganisationMembers имеет UserId в качестве первого поля, так как обычно у пользователей гораздо больше пользователей, чем у организаций, и вы, вероятно, захотите показать, какие организации пользователь является участником чаще, чем обратный.
- Индекс по OrganisationId в OrganisationMembers должен обслуживать запросы, в которых должен отображаться список участников для конкретной организации.
Литература: