10th May 2010, 03:09 pm
Diszket kellett bővíteni egy SQL clusterben, a lehető legkevesebb leállással, úgyhogy úgy döntöttem, hogy folytatom, amiben jó kezdek lenni: scriptelek. A cluster diszkek hozzáadása önmagában nem nagy szám (most felhördül legalább 28 ember, akinek már voltak rossz élményei a témában – nekem is, de a lekapcsolt többi node majdnem mindig dobott a dolgon), a jó rész az, hogy az SQL csak azokat a diszkeket használja, amiken dependál a service, a dependenciát pedig csak leállított helyzetben lehet állítgatni. Itt jön jól a script, hogy ne kelljen klikkelni, míg megöregszem. Ezúttal a cluster.exe volt a műtéti alany, az eredmény pedig alant látható (a sql12clus clustert megtámogatva):
cluster.exe sql12clus resource "SQL Server" /Offline
cluster.exe sql12clus resource "SQL Server" /AddDependency:"K: BillingData"
cluster.exe sql12clus resource "SQL Server" /AddDependency:"L: BillingLog"
cluster.exe sql12clus resource "SQL Server" /Online
Azaz leállít, dependenciát hozzáad, elindít. Egy öröm volt.
27th April 2010, 09:45 am
Az SQL 2008 R2 előadásomon a Lurdy Házban mutattam egy PS scriptet, ami a következő igényt elégíti ki: egy fájlrendszeren lakó könyvtárban lévő backup fájlokból kinyalja a backup információkat. Íme a script:
function List-Backups(
[string] $filename, ##fájl vagy könyvtárnév, dir parancs számára emészthető input kell
$Html, ## HTML fájl output neve, .\ prefix kell neki lokális esetén
$servername = '.' ## az SQL Server, aki lefuttatja a restore headeronly parancsot
) {
## a tulajdonságok, amik kellenek - teljes lista a BOL-ban
$proplist = ('Position', 'DatabaseName','ServerName','BackupFinishDate','DatabaseVersion')
## mint fent, csak a filename mezővel prefixeltem. igénytelen, de gyors megoldás,
$proplist2 = ('FileName', 'Position', 'DatabaseName','ServerName','BackupFinishDate','DatabaseVersion')
## ez a tömb tárolja a teljes listát
$allbck = @()
foreach ($file in (dir $filename)) ## ezért kellett dir kompatibilis input
{
## lefut a restore headeronly...
$backups = invoke-sqlcmd -ServerInstance ".\mysql" -Query "restore headeronly from disk = '$($file.FullName)'"
$bck = @()
## a kiválasztott mezoket eltesszük a $bck változóba.
## Igazából perzisztált scriptben nem illik olyan shortcutokat használni, mint % (foreach) meg ? (where)
$backups|select $proplist|%{$bck += $_}
## hozzáadjuk a fájlnevet is...
$bck |add-member noteproperty filename $file.FullName
## ... és a kibövitett listát eltesszük az összegzett listába
$allbck += $bck|select $proplist2
} #foreach $file
## kiírjuk az összegzett listát a standard outputra - ez a függvény kimenete
$allbck
## ha meg lett adva HTML fájlnév, akkor abba is kitoljuk a táblázatot, és meg is nyitjuk. Itt lehetne kezelni a .\ hiányát, de nem tettem, lustaságból
if ($Html)
{
$allbck|ConvertTo-Html|Out-file $Html
## itt nyitjuk meg, az alkalmazás a default app a megadott kiterjesztéshez, tehát a böngészőnk htm(l)-nél
invoke-expression $Html
} #if $html
} #function List-Backups
## És nézzünk néhány példát is:
## nézzük meg a D:\SQLData\Backups könyvtár tartalmát, HTML-ben is
List-Backups D:\SQLData\Backups .\lista.html
## nézzünk meg egyetlen fájlt a konzolon
List-Backups D:\SQLData\Backups\Full.BAK
##keressük meg a Billing adatbázis legfrissebb full backupját tartalmazó fájlt és a backup pozícióját a megadott könyvtárban
List-Backups D:\SQLData\Backups | ?{$_.DatabaseName -eq 'Billing' -and $_.BackupTypeDescription -eq 'DATABASE'} | `
Sort -prop BackupFinishDate -desc| select Filename, Position -first 1
Az utolsó parancsba beletoltam több mindent is. A ? (where) a szűrést hivatott bemutatni, a -eq és az -and a vicces operátorokat, amit el is rontottam a demóban, a backtick a többsoros parancs sorvégét jelzi, a többi meg magától értetődő, de azért jó látni, hogy a lehetőségek szinte korlátlanok.
6th April 2010, 09:22 pm
Időről időre visszatérő probléma: melyik tárolt eljárást érinti egy adott tábla módosítása, melyik SP-ben van deprecated (elavult) (NOLOCK) hint, effélék – szóval keresni kell a definíciókban. Ezt sokféleképpen megtehetjük, a legkényelmesebb a definíciók felolvasása. Régebben az INFORMATION_SCHEMA.ROUTINES ANSI standard metatáblát használtam erre, most már váltottam a meglehetősen nem intuitív nevű sys.sql_modules rendszernézetre. A különbség egyébként nem nagy – a standardban csak az első 4000 karakter látszik, a MSSQL-specifikus pedig nvarchar(max), tehát hajszálnyit több fér bele.
Ebből született a tárolt eljárásban stringet kereső tárolt eljárás. Két paramétert vár: a stringet, amire keresni akarunk és az adatbázis nevét, amiben keresni akarunk. Ha az egész szerveren szeretnénk keresni, akkor használhatjuk az undocumented sp_MSforeachdb tárolt eljárást.
CREATE PROCEDURE dbo.spFindTextInSP
@string nvarchar(1000),
@dbname sysname = ''
AS
if (isnull(@dbname,'') = '')
set @dbname = db_name()
declare @q nvarchar(2000)
set @q = 'select quotename(object_schema_name(object_id,db_id('''+ @dbname + '''))) + ''.'' + quotename(object_name(object_id,db_id(''' + @dbname + '''))) AS matching_objects from ' + @dbname + '.sys.sql_modules
where definition like ''%' + @string + '%'''
exec(@q)
GO
-- és két minta felhasználás
exec dbo.spFindTextInSp 'alert'
exec dbo.spFindTextInSp 'alert', 'Customer_archiv'
18th March 2010, 08:04 am
Egy hónapja ígértem meg Tibornak azt a PowerShelles log shipping megoldást, amit használtunk SQL 2000-2005 migrációra. Az alapgondolat a következő: a 2000-es szerveren csinálunk egy log backup jobot, ami már az új szerverre, UNC-n keresztül teszi le a backup fájlokat. Ez egy sima T-SQL job. A 2005-ös szerveren pedig egy Operating System jobstep lakik, ami egy powershell scriptet futtat. A jobstep maga kb. ennyi: powershell.exe D:\mssql\MigrateMyDB.ps1. Ez most egy bedrótozott verzió, de elég egyszerűen átalakítható paraméterezhetővé, és akkor egy scripttel lehet több adatbázist is tutujgatni.
Continue reading ‘Log shipping PowerShell scripttel’ »
17th January 2010, 03:49 am
Az új verzió mindig jobb, szebb, gyorsabb, kényelmesebb, stb. És tényleg: most először kellett elmozgatnom SQL 2008 szerver rendszeradatbázisait, és király volt. Aki csinált ilyet 2005 vagy 2000 alatt, az tudja, hogy milyen szívás mindenféle hülye trace flaggel indítgatni a SQL-t, aztán rossz sorrendben attacsolni a modelt meg az msdb-t. Ehhez képest az SQL 2008-ban négyféle adatbázis van:
- Resource: Ő már nem is az adatfájloknál, hanem a programbinárisoknál lakik, hozzá se lehet nyúlni (és nem is kell).
- master: Változatlanul, a service startup paraméterét kell átírni.
- tempdb: Változatlanul alter database és nem kell fájlt másolni.
- a többi: (igen, model, msdb is többi) Alter database, szerver leáll, fájlmásolás, szerver start.
Annyira egyszerű volt, hogy lescripteltem az egészet, egy SQL, egy Powershell:
ALTER DATABASE model MODIFY FILE (NAME = modeldev, FILENAME = 'D:\mssql10\db_data\model.mdf')
ALTER DATABASE model MODIFY FILE (NAME = modellog, FILENAME = 'E:\mssql10\db_logs\modellog.ldf')
ALTER DATABASE tempdb MODIFY FILE (NAME = tempdev, FILENAME = 'D:\mssql10\db_data\tempdb.mdf')
ALTER DATABASE tempdb MODIFY FILE (NAME = templog, FILENAME = 'E:\mssql10\db_logs\templog.ldf')
ALTER DATABASE msdb MODIFY FILE (NAME = MSDBData, FILENAME = 'D:\mssql10\db_data\MSDBData.mdf')
ALTER DATABASE msdb MODIFY FILE (NAME = MSDBLog, FILENAME = 'E:\mssql10\db_logs\MSDBLog.ldf')
# atirjuk a registryben a startup parametereket
Set-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.INSTANCENAME\MSSQLServer\Parameters' -name "SQLArg0" -value "-dD:\mssql10\db_data\master.mdf"
Set-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.INSTANCENAME\MSSQLServer\Parameters' -name "SQLArg2" -value "-eD:\mssql10\SrvLogs\ERRORLOG"
Set-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.INSTANCENAME\MSSQLServer\Parameters' -name "SQLArg1" -value "-lE:\mssql10\db_logs\mastlog.ldf"
# SQL stop - a force azert kell, h a dependens service-ek is megalljanak
Stop-Service 'MSSQL$INSTANCENAME' -Force
Start-Sleep 10
# kopi adatbazis fajlok
Move-Item 'D:\mssql10\db_data\MSSQL10.INSTANCENAME\MSSQL\DATA\*.mdf' 'D:\mssql10\db_data'
Move-Item 'D:\mssql10\db_data\MSSQL10.INSTANCENAME\MSSQL\DATA\*.ldf' 'E:\mssql10\db_logs'
#Start-Service - az agent elinditja a SQL-t magat is
Start-Service 'SQLAgent$INSTANCENAME'
És kész is vagyunk… Scriptelni jó.