Ani Azure ani AWS nie wspierają funkcji FILESTREAM w bazach Microsoft SQL Server. Uniemożliwia to migrację z lokalnej bazy danych do chmury. Możemy sobie z tym jednak poradzić bez konieczności modyfikacji aplikacji. Wszytko, co musimy zrobić, to odpowiednio zmodyfikować bazę lub plik backupu.
Restore backup’u
Musimy pracować lokalnie na instancji, która faktycznie wspiera funkcję FILESTREAM. Możemy to zweryfikować następującym zapytaniem
SELECT
SERVERPROPERTY('FileStreamShareName') as Share_Name,
SERVERPROPERTY('FIleStreamConfiguredLevel') as Config_Level,
SERVERPROPERTY('FileStreamEffectiveLevel') as Effective_Level
Znaczenie otrzymanych wartości jest następujące:
- 0 – nie ma wsparcia
- 1 – wsparcie dla sesji TSQL
- 2 – wsparcie dla sesji TSQL i Win32
Jeśli widzimy 1 lub 2, to nasza instancja wspiera FILESTREAM i możemy odtworzyć backup.
Zaczynamy od wyciągnięcia prawidłowej nazwy bazy danych z pliku backupu
RESTORE HEADERONLY FROM DISK = 'C:\katalog_backupow\moja_baza.bak'
Weryfikujemy ścieżki, pod które będzie się chciała odtworzyć baza
RESTORE FILELISTONLY FROM DISK = 'C:\katalog_backupow\moja_baza.bak'
W tym przykładzie dostajemy następujący wynik:
LogicalName | PhysicalName |
moja_baza | D:\DATA\moja_baza\moja_baza.mdf |
moja_baza_log | D:\DATA\moja_baza\moja_baza_log.ldf |
moja_baza_filestream | D:\DATA\moja_baza\moja_baza_filestream |
Zapamiętujemy nazwę logiczną [moja_baza_filestream]
Skomplikujmy sobie nieco scenariusz – załóżmy, że na naszej maszynie nie ma dysku D:\
za to mamy dużo miejsca na dysku E:\
Jesteśmy zatem zmuszeni użyć metody RESTORE WITH MOVE
Będzie to wyglądać tak:
RESTORE DATABASE
[moja_baza]
FROM DISK = 'C:\katalog_backupow\moja_baza.bak'
WITH
MOVE 'moja_baza' TO 'E:\DATA\moja_baza\moja_baza.mdf',
MOVE 'moja_baza_log' TO 'E:\DATA\moja_baza\moja_baza_log.ldf',
MOVE 'moja_baza_filestream' TO 'E:\DATA\moja_baza\moja_baza_filestream'
Zabezpieczenie danych
Pewną niedogodnością jest to, że musimy z góry znać każdą tabelę, która korzysta z FILESTREAM’u. Najlepiej jest zapytać o to opiekuna aplikacji. W naszym przykładzie będzie tylko jedna taka tabela: [moja_schema].[moja_tabela_1]
W celu zachowania danych tworzymy tabelę przejściową o nazwie [moja_schema].[moja_tabela_2]
Jej struktura musi być zgodna z [moja_schema].[moja_tabela_1]
Celowo nie używamy metody SELECT INTO.
CREATE TABLE [moja_schema].[moja_tabela_2] (
[file_id] UNIQUEIDENTIFIER DEFAULT NEWID() PRIMARY KEY NOT NULL,
[file_stream] varbinary(max) NULL,
[file_name] nvarchar(255) NOT NULL
ON [PRIMARY];
INSERT INTO [Documents].[Files_v2][Documents].[Files_v2] (
[file_id],
[file_stream],
[file_name]
)
SELECT
[file_id],
[file_stream],
[file_name]
FROM [moja_schema].[moja_tabela_1]
Usunięcie FILESTREAM’u
Jeżeli dotarliśmy do tego miejsca, to znaczy, że mamy sprawną bazę danych i zabezpieczyliśmy dane przed ich utratą. Możemy zatem przystąpić do usuwania FILESTREAM’u.
Ustalamy nazwę filegroup’y, która obsługuje FILESTREAM. W tym przykładzie to [FILESTREAM_FILEGROUP]
SELECT * FROM sys.filegroups
Dropujemy tabelę i usuwamy filegrupę. Poniższy przykład demonstruje również jak poradzić sobie z ewentualnym kluczem obcym odnoszącym się do usuwanej tabeli.
ALTER TABLE [moja_schema].[tabela_z_kluczem_obcym] DROP CONSTRAINT [moj_constraint]
DROP TABLE [moja_schema].[moja_tabela_1]
ALTER Database [moja_baza] REMOVE FILE [moja_baza_filestream]
ALTER Database [moja_baza] REMOVE FILEGROUP [FILESTREAM_FILEGROUP]
Zamieniamy tabelę przejściową na tabelę docelową. Drugi argument poniższej komendy celowo nie ma podanej schemy
EXEC sp_rename 'moja_schema.moja_tabela_2','moja_tabela_1'
Na koniec odtwarzamy wspomniany wyżej klucz obcy. Powinno się to udać bez problemu, jeżeli INSERT z SELECT’em przeszły bezbłednie
ALTER TABLE
[moja_schema].[tabela_z_kluczem_obcym]
WITH CHECK ADD CONSTRAINT [moj_constraint]
FOREIGN KEY([file_id])
REFERENCES [moja_schema].[moja_tabela_1] ([file_id])