Automatizovaná záloha všech databází na SQL Express

Express edice SQL Serveru 2008 je dostatečně robustní pro běh řady aplikací, přestože je dostupná zdarma. Většímu nasazení mnohdy brání absence SQL Agenta a Maintenance plánů, které u "velkého" SQL serveru zajišťují automatizovanou údržbu a zálohu databází. S trochou šikovnosti lze ale databáze automaticky zálohovat i u Express edice.

Maintenance plány fungují tak, že vám umožní například zazálohovat všechny databáze nebo na nich provést nějaké údržbové úkoly. SQL Server Agent, který se o ně stará, je jakýsi "task scheduler", který žije uvnitř SQL Serveru a stará se o automatické spouštění úloh.

Express edice nic takového nemá a pokud chceme například automaticky zálohovat všechny databáze, je třeba to naskriptovat vlastními silami. Princip fungování je velmi jednoduchý: V první řadě vytvoříme SQL dávku, která při spuštění projede seznam všech databází a pomocí příkazu BACKUP DATABASE je zazálohuje. Ve druhé řadě pak napíšeme dávkový soubor (CMD), ve kterém pomocí utility SQLCMD dříve vytvořený SQL skript spustíme. Aby se nám zálohy na disku nehromadily až do jeho úplného zaplnění, automaticky rovněž smažeme všechny záložní soubory, které jsou starší než definovaný počet dnů. Tento dávkový soubor pak pomocí systémového task scheduleru spustíme například jednou za den.

ExpressBackup.sql

Takhle bude vypadat soubor ExpressBackup.sql, který provede vlastní zálohování:

/******************************************************************************

** ALL DATABASE BACKUP SCRIPT FOR MICROSOFT SQL SERVER EXPRESS EDITION 2008  **

** Copyright (c) Michal A. Valasek, Altairis, 2009                           **

** http://www.aspnet.cz/ | http://www.altairis.cz/ | http://www.rider.cz/    **

** ------------------------------------------------------------------------- **

** When running from command line:                                           **

**  - set BackupFilePath environment variable                                **

**  - see ExpressBackup.cmd for example                                      **

** When running from SQL management studio:                                  **

**  - enable Query -> SQLCMD mode                                            **

**  - uncomment the ":setvar" line below and specify path                    **

******************************************************************************/

 

-- :setvar BackupFilePath "D:\SqlBackup\" -- include trailing backslash!!

 

-- Declare variables used in the script

DECLARE

  @timestamp AS nvarchar(20),

  @current_id AS int,

  @current_name AS nvarchar(max),

  @current_file AS nvarchar(max)

 

-- Create file name timestamp (YYYYMMDD_hhmmss format)

SET @timestamp = CONVERT(nvarchar, GETDATE(), 20)

SET @timestamp = REPLACE(@timestamp, '-', '')

SET @timestamp = REPLACE(@timestamp, ':', '')

SET @timestamp = REPLACE(@timestamp, ' ', '_')

 

-- Get initial database ID

SELECT @current_id = MIN(database_id) FROM sys.databases WHERE name <> 'tempdb'

 

-- Go trough all databases

WHILE @current_id IS NOT NULL BEGIN

  -- Get database name and backup file

  SELECT @current_name = name FROM sys.databases WHERE database_id = @current_id

  SET @current_file = '$(BackupFilePath)' + @current_name + '_' + @timestamp + '.bak'

 

  -- Backup database

  PRINT 'Backing up database ' + @current_name + ' to ' + @current_file

  BACKUP DATABASE @current_name TO  DISK = @current_file WITH NOINIT

  PRINT NULL

 

  -- Get next database

  SELECT @current_id = MIN(database_id) FROM sys.databases WHERE name <> 'tempdb' AND database_id > @current_id

END

Tato dávka postupně zazálohuje všechny databáze do souboru "NázevDB_YYYYMMDD_hhmmss.bak" ve složce určené SQLCMD proměnnou "BackupFilePath". Výše uvedený skript není primárně určen k tou, aby byl spouštěn interaktivně z Management Studia (i když i to je možné, pokud zapneme SQLCMD režim, viz komentář), ale právě ke spuštění pomocí řádkové utility SQLCMD. V takovém případě se konstrukce $(NázevProměnné) ve skriptu zamění za hodnotu systémové proměnné NázevProměnné.

ExpressBackup.cmd

To je myslím hezky vidět v souboru ExpressBackup.cmd, který dělá v podstatě jenom tři věci: nastaví systémovou proměnnou, zavolá výše uvedenou SQL dávku a poté vymaže všechny záložní soubory starší než 7 dnů (posuzuje to podle data poslední změny souboru, ne podle jeho názvu).

@ECHO OFF

 

REM -- Set path to backup databases to - referenced from the SQL script

REM -- This path must include trailing backslash!

SET BackupFilePath=D:\SqlBackup\

 

REM -- Call SQLCMD with parameters needed to connect to SQL Server

SQLCMD -S .\SqlExpress -E -i ExpressBackup.sql

 

REM -- Delete all backup files older than 7 days

ECHO Deleting backups older than 7 days...

FORFILES /P %BackupFilePath% /M *.bak /D -7 /C "CMD /C DEL /Q @FILE"

Tento soubor (zejména cestu k záložním souborům a volání SQLCMD) si můžete upravit dle potřeby.

Poslední krok pak spočívá v tom, že soubor ExpressBackup.cmd zavoláte jednou za den pomocí systémového plánovače úloh.

Ačkoliv je tento návod ušit na míru Express edici, můžete ho v případě nutnosti použít i na vyšší edice. Nicméně obecně to nedoporučuji, SQL Server Agent umí mnohem víc a vyplatí se s ním naučit zacházet.

Titulek:
Text komentáře:
Vaše jméno:
Váš e-mail: (nebude zveřejněn)

WWW stránka:
Opište text z obrázku:
odpovědětodpovědět Gravatar

Díky za tip

28.12.2009 21:46:4528.12.2009 21:46:45 ArciArci ---.net.upc.cz

My už nějakou dobu používáme http://www.mssqltips.com/tip.asp?tip=148… ale uznávám, že tohle je lepší varianta.

Tím řešením jsem se velmi volně inspiroval, ale přijde mi strašně komplikované. Takže jsem to napsal celé znovu, snad jenom ta WHILE smyčka tam zůstala - je to docela elegantní řešení.

odpovědětodpovědět Gravatar

Rád se také podělím

3.2.2010 14:56:073.2.2010 14:56:07 HansHans ---.18.broadband16.iol.cz

Zdravím,

kdysi jsme vygoogloval tento script, který mi zatím funguje spolehlivě. Mám k tomu ještě spouštěcí *.bat soubor, kde jsem použil i LZH knihovnu pro kompresi zálohy.

DECLARE @DBName varchar(255)

DECLARE @DATABASES_Fetch int

DECLARE DATABASES_CURSOR CURSOR FOR

select

DATABASE_NAME = db_name(s_mf.database_id)

from

sys.master_files s_mf

where

-- ONLINE

s_mf.state = 0

-- Only look at databases to which we have access

and has_dbaccess(db_name(s_mf.database_id)) = 1

-- Not master, tempdb or model

and db_name(s_mf.database_id) not in ('Master','tempdb','model','msdb')

group by s_mf.database_id

order by 1

OPEN DATABASES_CURSOR

FETCH NEXT FROM DATABASES_CURSOR INTO @DBName

WHILE @@FETCH_STATUS = 0

BEGIN

declare @DBFileName varchar(256)

set @DBFileName = replace(replace(@DBName,':','_'),'\','_') + '.' +'bak'

exec ('BACKUP DATABASE [' + @DBName + '] TO DISK = N''c:\Users\xxx\Documents\BACKUP_fullSQL\Backup_data\BAK\' +

@DBFileName + ''' WITH NOFORMAT, INIT, NAME = N''' +

@DBName + '-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, STATS = 100')

FETCH NEXT FROM DATABASES_CURSOR INTO @DBName

END

CLOSE DATABASES_CURSOR

DEALLOCATE DATABASES_CURSOR

odpovědětodpovědět Gravatar

RE: Rád se také podělím

Jo, to je principiálně totožné, jenom pro načítání názvů databází používáte kurzor místo smyčky. Trochu by mi vadilo, že to dělá jenom jednu zálohu a ne víc verzí zpětně, ale záleží na podmínkách.

odpovědětodpovědět Gravatar

RE: Rád se také podělím

3.2.2010 15:14:443.2.2010 15:14:44 HansHans ---.18.broadband16.iol.cz

:-) časové razítko jsem tam měl také, ale tato verze je takovou berličkou, abych nemusel odmazávat staré zálohy (*.bak) , starou zálohu tedy přepisuji a časové razítko si dávám k té zkomprimované, kterou vytvářím přes LZH knihovnu.

odpovědětodpovědět Gravatar

Ponechání x posledních záloh na "velkém" SQL serveru

3.2.2010 15:06:353.2.2010 15:06:35 HansHans ---.18.broadband16.iol.cz

Měl byh ještě otázku, nevěděl byste jak nastavit automatické zálohování na "plném" SQL serveru tak, aby ponechávalo posledních 7 záloh? Měl jsem dojem, že se to řídí parametrem a údajem o expiraci (backup set will expire) zálohy v Maintenance plánu zálohování, ale po vyzkoušení jsem zjistil, že tomu tak není. Má s tím někdo zkušenosti?

odpovědětodpovědět Gravatar

RE: Ponechání x posledních záloh na &quot;velkém&quot; SQL serveru

Je na to task v maintenance plánech. Podívejte se sem:

http://www.mstv.cz/it/videos/373/Nastave…

odpovědětodpovědět Gravatar

RE: Ponechání x posledních záloh na &amp;quot;velkém&amp;quot; SQL serveru

22.2.2010 9:01:3322.2.2010 9:01:33 HansHans ---.18.broadband16.iol.cz

Zdravím, díky za info a link na zajímavá videa. Ale mám s tím zálohováním malinko problém. Task jsem si do plánu přidal, ale nějak nefunguje. Na disku mi stále zůstávají soubory bez odmazání. Když se podívám do logu, tak tam nikde není zmínka o tom, že by např. nemohl smazat soubor zálohy kvůli právům složky. V délce trvání tasku je 00:00:00 a vše se tváří, jako by to proběhlo. :-(

odpovědětodpovědět Gravatar

expressmaint

19.2.2010 8:27:2819.2.2010 8:27:28 manasjmanasj 94.124.184.---

Doporučuji řešení pomocí uložené procedury expressmaint http://www.sqldbatips.com/showarticle.as…, kromě záloh umí i jiné údržbové záležitosti (transakční logy, kontrola integrity, index rebuilding, mazání starých souborů, apod.) Používám jej už od MS SQL 2005 Express a jsem s ním naprosto spokojen.

odpovědětodpovědět Gravatar

RE: expressmaint

Dobrý den, měl bych problém při zálohování databáze pomocí Expressmaint utility v1.6.0.0 v OS W2003 R2. Samotná uživatelská DB se vytvoří, ale nějak přestalo fungovat vytváření systemových DB ( master, model, msdb ). Uvádím výpis z logu. Na co narazím při případné obnově bez těchto položek ? Marek

[1] Database master: Backup starting at 10.6.2010 22:45:06

Backup failed for Server 'SERVER01\SQLExpress'.

An exception occurred while executing a Transact-SQL statement or batch.

BACKUP DATABASE permission denied in database 'master'.

BACKUP DATABASE is terminating abnormally.

[2] Database model: Backup starting at 10.6.2010 22:45:06

Backup failed for Server 'SERVER01\SQLExpress'.

An exception occurred while executing a Transact-SQL statement or batch.

The server principal "Domena\Administrator" is not able to access the database "model" under the current security context.

BACKUP DATABASE is terminating abnormally.

[3] Database msdb: Backup starting at 10.6.2010 22:45:06

Backup failed for Server 'SERVER01\SQLExpress'.

An exception occurred while executing a Transact-SQL statement or batch.

BACKUP DATABASE permission denied in database 'msdb'.

BACKUP DATABASE is terminating abnormally.

Systémové databáze obsahují (zjednodušeně řečeno) nastavení SQL serveru, tj. jaké databáze tam existují, nastavení maintenance plánů, uživatele a podobně.

Pokud vám jde o zachování dat a funkčnosti jednotlivých databází a nemáte tam nějakou komplikovanou instalaci, kterou by vám činilo problém vytvořit znovu, stačí že máte zálohované uživatelské databáze. Pokud chcete mít možnost obnovit kompletní funkčnost serveru jako takového, zálohovat je musíte.

Obšírnější pojednání o systémových databázích najdete na http://msdn.microsoft.com/en-us/library/…

odpovědětodpovědět Gravatar

RE: expressmaint

Děkuji za odpověď. Dá se použit uvedený script "ExpressBackup.sql" i pro SQL 2005 Express ? Když ano, je možné ho spustit i za chodu aplikace ?

Měl by fungovat i na SQL 2005, ale nezkoušel jsem ho. Nevím, co myslíte pod pojmem "za běhu aplikace", ale zálohy se běžně prováději za provozu SQL serveru, samozřejmě.

odpovědětodpovědět Gravatar

RE: expressmaint

Po vyzkoušení mi to u všech nalezených DB vypíše :

Backing up database master to D:\SqlBackup\master_20100614_133417.bak

Msg 3123, Level 16, State 1, Server SERVER01\SQLEXPRESS, Line 79

Invalid database name '?G????.....' specified for backup or restore operation.

Msg 3013, Level 16, State 1, Server SERVER01\SQLEXPRESS, Line 79

BACKUP DATABASE is terminating abnormally.

Ehm, ale tam žádný řádek 79 není. Co to vlastně používáte? Pokud tu utilitu ExpressMaint, která byla zmíněna v diskuzi, tak s tou nemám žádné zkušenosti. Pokud moji, měla by fungovat, ale IMHO nemůže vracet takovou chybu, protože nemá žádný řádek 79.

odpovědětodpovědět Gravatar

RE: expressmaint

Použil jsem Váš script + dávku cmd. Když spustím jen script tak se otevře SQL Server Management Studio Express a na řádku 79 je - BACKUP DATABASE @current_name TO DISK = @current_file WITH NOINIT

To nemůže být můj skript. Ten má 45 řádků celkem. Něco děláte špatně.

Jinak jsem si právě ověřil, že to chodí i proti SQL Serveru 2005.

odpovědětodpovědět Gravatar

RE: expressmaint

Na úvodu této stránky zkopíruji text až po End = 46 řádků ( po úpravě mezer mezi řádky. Asi to po zkopírování rozhazují mezery, ale podstatné přece je, že se to vždy zastaví na stejném řádku. Nebo musím v uvedeném scriptu ještě něco změnit ?

Ve skriptu nemusíte měnit nic.

Pokud vám to hlásí, že nemůže najít databázi s nějakým pochybným názvem plným otazníků, tak mne napadají v zásadě dvě možnosti:

a) ten skript jste špatně zkopíroval a někde je tam nějaký garbage - tomu naznačuje i chaos okolo číslování řádků.

b) máte poškozenou databázi master, ve které jsou uloženy názvy ostatních databází a vrací vám to nějaké nesmysly. Zkuste si vypsat seznam databází příkazem "SELECT database_id, name FROM sys.databases", jestli tam ty nesmysly budete mít taky.

V každém případě je ale chyba někde na vaší straně, ten skript sám o sobě je v pořádku a funguje i na verzi 2005. Je ostatně tak jednoduchý, že na něm není v zásadě co zkazit.

odpovědětodpovědět Gravatar

RE: expressmaint

select vypíše správné názvy DB ( master,model ...). Zkusil jsem backup ručně z management Studia u db Master a výsledek uvádím níže. Uživatelské db projdou bez problémů. Nenapadá Vás co by mohlo vést k odmítnutí k syst.db ?

TITLE: Microsoft SQL Server Management Studio Express

------------------------------

Backup failed for Server 'SERVER01\SQLEXPRESS'. (Microsoft.SqlServer.Express.Smo)

For help, click: http://go.microsoft.com/fwlink?ProdName=…ProdVer=9.00.3042.00&EvtSrc=Microsoft.SqlServer.Management.Smo.ExceptionTemplates.FailedOperationExceptionText&EvtID=Backup+Server&LinkId=20476

------------------------------

ADDITIONAL INFORMATION:

System.Data.SqlClient.SqlError: BACKUP DATABASE permission denied in database 'master'. (Microsoft.SqlServer.Express.Smo)

For help, click: http://go.microsoft.com/fwlink?ProdName=…ProdVer=9.00.3042.00&LinkId=20476

------------------------------

BUTTONS:

OK

------------------------------

odpovědětodpovědět Gravatar

Pohodlné zálohování

Bezvadné, funguje. Díky

odpovědětodpovědět Gravatar

RE: expressmaint

V části deklarací použijte "varchar" místo "nvarchar":

-- Declare variables used in the script

DECLARE

@timestamp AS varchar(20),

@current_id AS int,

@current_name AS varchar(max),

@current_file AS varchar(max)

  • Altairis
  • Nemesis
  • Microsoft MVP
  • IIS
  • ASP.NET