SQL Server posiada kilka mechanizmów umożliwiających przechowywanie dużej ilości danych np. plików graficznych.
FileStream
Pierwszych z nich jest FILESTREAM. Przed pojawieniem się typu FILESTREAM, programiści najczęściej zapisywali pliki sami na dysku a lokalizacje przechowali w bazie danych. Rozwiązanie dobre jednak kłopoty powstały w momencie synchronizacji – co jeśli ktoś usunie jakiś plik z dysku? FILESTREAM to nic innego jak zapisanie pliku w bazie danych. W przeciwieństwie do typu varbinary, FILESTREAM przechowywany jest w osobnym pliku a nie w pliku tabeli. Zwiększa to wydajność, jednak zwykłe poleca się go dla danych większych niż 1 MB.
Najpierw jednak należy skonfigurować odpowiednio bazę danych. Wszystko można zrobić z poziomu T-SQL jednak w poście pokażę jak to wykonać w SQL Server Management Studio. Najpierw klikamy na bazie danych i przechodzimy do zakładki FIleGroups a następnie dodajemy nowy FileStream (FileStreamTest):
Następnie musimy podłączyć utworzoną grupę do konkretnego pliku (folderu). Przechodzimy do zakładki Files i tworzymy nowy plik bazy:
Jeśli zajrzymy do utworzonego właśnie folderu zobaczymy plik o rozszerzeniu hdr (filestream.hdr) zawierający metadane, $FSLOG służący jako transaction log, oraz kilka folderów których nazwy stanowią globalne identyfikatory – przechowują one już właściwe dane.
Możemy teraz przejść do utworzenia tabeli. Kod:
create table SampleTable ( ID uniqueidentifier not null rowguidcol unique, DATA varbinary(max) FILESTREAM null )
Warto zauważyć, że tabela z kolumną FileStream musi zawierać unikalny w skali globalnej (rowguidcol) identyfikator. Tabela została utworzona i możemy przejść do umieszczania danych. W momencie gdy usuwamy dane FILESTREAM tak naprawdę zostaną one permanentnie usunięte z dysku gdy SQL Server odpali pewien proces czyszczący te dane. Spróbujmy dodać dane z poziomu T-SQL:
DECLARE @SomeData AS VARBINARY(MAX) -- zaladowanie danych SELECT @img = CAST(bulkcolumn AS VARBINARY(MAX)) FROM OPENROWSET( BULK 'C:\obrazek.jpg', SINGLE_BLOB ) AS x INSERT INTO Images (ID, Image) SELECT NEWID(), @img
Z poziomu c#: (odczyt):
SqlCommand sqlCommand = new SqlCommand(); sqlCommand.Connection = con sqlCommand.CommandText = "SELECT Image FROM Images " + _ "WHERE ID = 'jakis_id'" byte[] buffer= = sqlCommand.ExecuteScalar(); MemoryStream memoryStream = new MemoryStream(buffer); Bitmap bitmap=new Bitmap(memoryStream);
Na koniec należy wspomnieć również o konfiguracji dostępu do FILESTREAM:
EXEC sp_configure filestream_access_level, 2 GO RECONFIGURE GO
Procedura przyjmuje jako parametry liczby 1,2,3 oznaczające kolejno dostęp wyłącznie za pomocą T-SQL, dostęp za pomocą systemu plików oraz dostęp z użyciem sieci (share).
Oczywiście istnieje wiele sposobów zapisu danych – nie tylko przez użycie tablicy bajtów.
Drugim mechanizmem jest czysty typ VARBINARY – bez atrybutu FILESTREAM. Proces wstawania, selekcji danych jest identyczny jednak parametry wydajnościowe są różne. Generalnie zasada jest prosta – dla małych plików wydajniejszy jest czysty VARBINARY ponieważ nie wiąże się on z dodatkowym czasem poświęconym na zapisywanie pliku w innej strukturze. Dla dużych (>1MB) lepiej używać FILESTREAM.