Ola Hallengrens Maintenance Solution: Backup, CHECKDB og indekser
SQL Server Maintenance Solution er en samling gratis T-SQL-skript for backup, integritetssjekk og indeks- og statistikkvedlikehold i SQL Server. Den er skrevet av den svenske DBA-en Ola Hallengren og er trolig den mest brukte vedlikeholdsløsningen for SQL Server i verden. Skriptene, dokumentasjonen og nyeste versjon finner du på ola.hallengren.com.
- Tre lagrede prosedyrer gjør jobben:
DatabaseBackup,DatabaseIntegrityCheckogIndexOptimize - Ett installasjonsskript,
MaintenanceSolution.sql, oppretter prosedyrene, loggtabellen og ferdige SQL Server Agent-jobber - Jobbene opprettes uten tidsplan. Du må selv bestemme når de skal kjøre
- Løsningen er gratis og åpen kildekode under MIT-lisensen
Hvorfor bruke Ola Hallengrens skript?
Du kan bygge vedlikeholdet selv eller bruke de innebygde vedlikeholdsplanene i SSMS. De fleste erfarne DBA-er velger likevel Hallengrens løsning, av flere grunner:
- Nye databaser tas med automatisk. Du velger databaser med nøkkelord som
USER_DATABASES, ikke med navn. - Indekser vedlikeholdes etter behov. Bare indekser som faktisk er fragmenterte og store nok, blir reorganisert eller bygget om.
- Alt logges. Hver kommando, med start- og sluttid og eventuelle feil, kan logges til tabellen
CommandLog. - Støtter det meste: availability groups, backup til Azure Blob Storage og S3, kryptering, komprimering og flere backupfiler i parallell.
- Godt testet: Løsningen har vært i bruk i mange år på tusenvis av servere, og den vant «Best Free Tool» i SQL Server Magazine Awards flere år på rad fra 2010 til 2013.
Løsningen støtter SQL Server 2017, 2019, 2022 og 2025, og Azure SQL Managed Instance, i alle utgaver. Har du eldre versjoner, finnes det eldre utgaver av skriptene på nettsiden. For Azure SQL Database finnes et eget skript med integritetssjekk og indeksvedlikehold. Backup håndterer Azure-plattformen selv.
Se også den generelle guiden om vedlikehold av SQL Server for hvorfor og hvor ofte de ulike oppgavene bør gjøres.
Hva løsningen består av
| Objekt | Type | Oppgave |
|---|---|---|
DatabaseBackup |
Lagret prosedyre | Full-, differensiell- og loggbackup, med verifisering og opprydding av gamle filer |
DatabaseIntegrityCheck |
Lagret prosedyre | Kjører DBCC CHECKDB eller de mer avgrensede CHECK-kommandoene |
IndexOptimize |
Lagret prosedyre | Reorganiserer eller bygger om indekser og oppdaterer statistikk |
CommandExecute |
Lagret prosedyre | Hjelpeprosedyre som kjører og logger hver kommando. Brukes av de tre andre |
CommandLog |
Tabell | Logg over alle kommandoer, med tidsbruk og feilmeldinger |
Installasjon
- Last ned
MaintenanceSolution.sqlfra ola.hallengren.com eller fra GitHub. - Åpne skriptet i SSMS og juster variablene øverst.
- Kjør skriptet som sysadmin.
- Legg inn tidsplaner på jobbene (se under).
Variablene øverst i skriptet styrer installasjonen. Et typisk oppsett ser slik ut:
USE [DBA] -- Databasen objektene skal opprettes i (standard er master)
DECLARE @CreateJobs nvarchar(max) = 'Y' -- Opprett SQL Server Agent-jobber
DECLARE @BackupDirectory nvarchar(max) = N'D:\Backup' -- NULL = serverens standard backupmappe
DECLARE @BackupURL nvarchar(max) = NULL -- Alternativ: backup til Azure Blob Storage eller S3
DECLARE @CleanupTime int = 168 -- Slett backupfiler eldre enn 168 timer (7 dager). NULL = aldri
DECLARE @OutputFileDirectory nvarchar(max) = NULL -- NULL = samme mappe som SQL Server-feilloggen
DECLARE @LogToTable nvarchar(max) = 'Y' -- Logg til tabellen CommandLog
Tips: Opprett gjerne en egen database for DBA-verktøy, for eksempel DBA, i stedet for å legge objektene i master. Databasen bør ikke være med i en availability group. Da holdes verktøyene samlet, og de er enkle å ta backup av og flytte.
Bruker du PowerShell-modulen dbatools, kan du installere alt med én kommando:
Install-DbaMaintenanceSolution -SqlInstance SQL01 -Database DBA `
-BackupLocation 'D:\Backup' -CleanupTime 168 -InstallJobs
Jobbene som opprettes
Skriptet oppretter disse SQL Server Agent-jobbene. Ingen av dem får tidsplan, så tabellen viser et forslag til hvor ofte de kan kjøre:
| Jobb | Forslag til tidsplan |
|---|---|
| DatabaseBackup - SYSTEM_DATABASES - FULL | Daglig |
| DatabaseBackup - USER_DATABASES - FULL | Ukentlig, eller daglig for små databaser |
| DatabaseBackup - USER_DATABASES - DIFF | Daglig de dagene det ikke tas fullbackup |
| DatabaseBackup - USER_DATABASES - LOG | Hvert 5.–15. minutt (databaser i Simple-modell hoppes over) |
| DatabaseIntegrityCheck - SYSTEM_DATABASES | Daglig |
| DatabaseIntegrityCheck - USER_DATABASES | Ukentlig |
| IndexOptimize - USER_DATABASES | Ukentlig, eller daglig hvis den bare oppdaterer statistikk |
| sp_delete_backuphistory | Ukentlig (sletter backuphistorikk i msdb eldre enn 30 dager) |
| sp_purge_jobhistory | Ukentlig (sletter jobbhistorikk eldre enn 30 dager) |
| CommandLog Cleanup | Ukentlig (sletter rader i CommandLog eldre enn 30 dager) |
| Output File Cleanup | Ukentlig (sletter gamle loggfiler fra jobbene) |
Legg også inn varsling til en operatør ved feil på alle jobbene. Et vedlikehold som feiler uten at noen merker det, er nesten like ille som intet vedlikehold.
Alle backupjobbene kjører med @Verify = 'Y' og @CheckSum = 'Y'. Hver backup blir altså verifisert med RESTORE VERIFYONLY, og sidene kontrolleres med sjekksummer.
DatabaseBackup
DatabaseBackup tar backup av én eller flere databaser og lager en mappestruktur per server, database og backuptype. Et typisk kall for fullbackup:
EXECUTE dbo.DatabaseBackup
@Databases = 'USER_DATABASES',
@Directory = N'D:\Backup',
@BackupType = 'FULL',
@Verify = 'Y',
@Compress = 'Y',
@CheckSum = 'Y',
@CleanupTime = 168,
@LogToTable = 'Y';
Velge databaser
Parameteren @Databases brukes på samme måte i alle tre prosedyrene:
| Verdi | Betydning |
|---|---|
SYSTEM_DATABASES | master, model og msdb |
USER_DATABASES | Alle brukerdatabaser |
ALL_DATABASES | Alle databaser |
AVAILABILITY_GROUP_DATABASES | Alle databaser i availability groups |
USER_DATABASES, -Db1 | Alle brukerdatabaser unntatt Db1 (minus utelater) |
%Db% | Alle databaser med «Db» i navnet (% er jokertegn) |
Viktige parametre
@BackupType:FULL,DIFFellerLOG.@Directory: Én eller flere mapper. Med flere mapper, adskilt med komma, fordeles backupen på flere filer. Utelates den, brukes serverens standard backupmappe.@CleanupTime: Antall timer backupfiler skal beholdes. Loggbackuper som er nyere enn siste full- eller differensielle backup, slettes aldri, så kjeden for gjenoppretting holdes intakt.@ChangeBackupType = 'Y': Tar fullbackup i stedet hvis en differensiell eller loggbackup ikke er mulig, for eksempel for en database som nettopp er opprettet.@URL: Backup til Azure Blob Storage eller S3-kompatibel lagring i stedet for disk.@Compress,@Encrypt,@CopyOnlyog@NumberOfFilesstyrer komprimering, kryptering, copy-only-backup og antall filer.
Filene får navn som inneholder server, instans, database, backuptype og tidspunkt. På en standardinstans kan en fullbackup av databasen Salg for eksempel hete SQL01_Salg_FULL_20261112_013000.bak og havne i mappen SQL01\Salg\FULL. For en navngitt instans blir instansnavnet med, adskilt med $. Loggbackuper får endelsen .trn.
Husk at en backup bare er så god som den siste vellykkede gjenopprettingen. Les mer om dette i guiden om backup og gjenoppretting.
DatabaseIntegrityCheck
DatabaseIntegrityCheck kjører DBCC CHECKDB og finner korrupsjon før den sprer seg til backupene dine:
EXECUTE dbo.DatabaseIntegrityCheck
@Databases = 'USER_DATABASES',
@CheckCommands = 'CHECKDB',
@LogToTable = 'Y';
For svært store databaser, der en full CHECKDB tar for lang tid, finnes det flere muligheter:
@PhysicalOnly = 'Y': Sjekker bare de fysiske strukturene. Det går mye raskere og fanger de fleste feil som skyldes lagringen.@CheckCommands = 'CHECKFILEGROUP'eller'CHECKTABLE': Deler sjekken opp, slik at du kan ta ulike filgrupper eller tabeller på ulike netter.@TimeLimit: Antall sekunder prosedyren kan starte nye sjekker. Når tiden er ute, startes ingen nye kommandoer, men den som kjører, får fullføre.
Med availability groups kan du styre hvilke replikaer som sjekkes, med @AvailabilityGroupReplicas.
IndexOptimize
IndexOptimize ser på fragmenteringen og størrelsen til hver indeks og velger handling ut fra det. Standardverdiene er:
| Fragmentering | Parameter | Standard handling |
|---|---|---|
| Under 5 % | @FragmentationLow |
Ingenting |
| 5–30 % | @FragmentationMedium |
Reorganisering, ellers ombygging online eller offline |
| Over 30 % | @FragmentationHigh |
Ombygging online, ellers offline |
Grensene styres med @FragmentationLevel1 (5) og @FragmentationLevel2 (30). Indekser med færre enn 1000 sider hoppes over (@MinNumberOfPages). Handlingene prøves fra venstre mot høyre, så INDEX_REBUILD_ONLINE brukes der utgaven og indeksen støtter det, og ellers INDEX_REBUILD_OFFLINE.
Viktig: Som standard oppdaterer IndexOptimize ikke statistikk, og jobben installasjonsskriptet oppretter, gjør det heller ikke. Utdatert statistikk er en av de vanligste årsakene til trege spørringer. Endre derfor jobbsteget til å inkludere statistikk.
Dette oppsettet, fra dokumentasjonen på nettsiden, er et godt utgangspunkt for de fleste:
EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y',
@LogToTable = 'Y';
@OnlyModifiedStatistics = 'Y' gjør at bare statistikk der data er endret siden forrige oppdatering, blir oppdatert. Det sparer mye tid.
Med rask SSD-lagring har fragmentering mindre betydning enn før, og mange DBA-er velger nå å oppdatere statistikk ofte og bygge om indekser sjeldnere. Da kan du kjøre en egen daglig jobb med @FragmentationMedium = NULL, @FragmentationHigh = NULL og @UpdateStatistics = 'ALL', i tillegg til en ukentlig jobb med indeksvedlikehold. Les mer om indekser i guiden om indekser.
Merk at IndexOptimize ikke vedlikeholder heaps (tabeller uten clustered indeks), og at indekser i availability groups bare vedlikeholdes på primærreplikaen.
Logging og feilsøking
Med @LogToTable = 'Y' lagres hver kommando i dbo.CommandLog. Installasjonsskriptet slår dette på for jobbene. Tabellen gjør det enkelt å se hva som har skjedd:
-- Feil den siste uken
SELECT TOP (50) DatabaseName, CommandType, StartTime, ErrorNumber, ErrorMessage
FROM dbo.CommandLog
WHERE ErrorNumber <> 0
AND StartTime > DATEADD(DAY, -7, GETDATE())
ORDER BY StartTime DESC;
-- Indeksoperasjonene som tok lengst tid den siste måneden
SELECT TOP (20) DatabaseName, ObjectName, IndexName, CommandType,
DATEDIFF(SECOND, StartTime, EndTime) AS Sekunder
FROM dbo.CommandLog
WHERE CommandType LIKE 'ALTER_INDEX%'
AND StartTime > DATEADD(MONTH, -1, GETDATE())
ORDER BY Sekunder DESC;
Jobbene skriver i tillegg en tekstfil per kjøring til mappen for SQL Server-feilloggen. Feiler en jobb, står den fullstendige feilmeldingen der, også når den ikke kom med i jobbhistorikken.
SQL Server Express
Skriptene fungerer også med Express, men Express har ikke SQL Server Agent, så jobbene kan ikke opprettes. Sett @CreateJobs = 'N' ved installasjon, og kjør prosedyrene fra Windows Oppgaveplanlegging med sqlcmd:
sqlcmd -E -S .\SQLEXPRESS -d DBA -b -Q "EXECUTE dbo.DatabaseBackup @Databases = 'USER_DATABASES', @Directory = N'D:\Backup', @BackupType = 'FULL', @Verify = 'Y', @CheckSum = 'Y', @CleanupTime = 168, @LogToTable = 'Y'"
Parameteren -b gjør at sqlcmd returnerer en feilkode hvis noe går galt, slik at Oppgaveplanlegging kan rapportere feilen.
Oppdatere til ny versjon
Ola Hallengren gir jevnlig ut nye versjoner med støtte for nye SQL Server-versjoner og feilrettinger. Sjekk hvilken versjon du har:
SELECT OBJECT_NAME(object_id) AS Prosedyre,
SUBSTRING(definition, CHARINDEX('--// Version: ', definition) + 14, 19) AS Versjon
FROM sys.sql_modules
WHERE definition LIKE '%--// Version: %';
Oppdater ved å laste ned nyeste MaintenanceSolution.sql og kjøre den mot samme database som før. Prosedyrene oppdateres, mens jobber som allerede finnes, ikke røres. Egne tidsplaner og parametre i jobbene beholdes derfor.
Gode råd
- Ikke endre standardverdiene i prosedyrene. Send heller parametrene i jobbsteget, og bruk alltid parameternavn. Da kan du oppdatere uten å miste tilpasningene.
- Sjekk tilganger på backupmappen. Tjenestekontoen til SQL Server må ha skrivetilgang til mappen eller nettverksdelingen.
- Legg backupene utenfor serveren. En backup på samme disk som databasen beskytter ikke mot disk- eller serverfeil, eller mot løsepengevirus.
- Test gjenoppretting jevnlig. Verifisering med
RESTORE VERIFYONLYer bra, men erstatter ikke en faktisk gjenoppretting. - Følg med på CommandLog og legg inn varsling på alle jobbene.
Lisens og kildekode
SQL Server Maintenance Solution er gratis å bruke, også kommersielt, og lisensiert under MIT-lisensen. Kildekoden ligger på GitHub, der du også kan melde feil og følge utviklingen.
Full dokumentasjon av alle parametre, flere eksempler og svar på vanlige spørsmål finner du på Ola Hallengrens nettside: ola.hallengren.com.