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.
Fajne, ale w zastosowaniach webowych się nie sprawdzi.
Do zdjęć raczej nie – byłaby to metoda dość mało wydajna.
Jednak do jakiś raportów, które nie są bezpośrednio ściągane (a analizowane itp.) jak najbardziej.
Czy ilość danych zapisanych tym typem liczy się do limitu bazy dla wersji EXPRESS?
Nie – 4gb w express są na reszte danych i limit nie zawiera FILESTREAM.