Filtered transactional replication vs performance

Elnézést az angol címért, de ez történt. Létrehoztam tegnap egy szűrt tranzakcionális publikációt (ez szerintetek jobb?), és ma ránéztem a szerverre, és azt láttam, hogy a logreader agent (naplóolvasó ügynök) le van maradva súlyos órákkal. Megnéztem a sysprocesses táblában, hogy mennyi erőforrást eszik, és azt láttam, hogy rohadt sokat. Állítgattam egy kicsit az agent paramétereken, de igazából nem értettem a helyzetet, és nem is segített a piszkálgatás.
Kénytelen voltam gondolkodni, és arra jutottam, hogy profiler kell nekem. És tényleg, a logreader agent spidjére szűrve elkezdtek záporozni a cpu-t és io-t evő eventek: dolgozta fel a filtert a szerencsétlen: where id in (select id from tabla2 where location_code = 144). Úgy döntöttem, hogy ez nekem annyira nem kell. Eldobtam az új publikációt, és… nem történt semmi változás a lemaradásban. Újraindítottam az agentet, semmi. Ekkor gondoltam, hogy le kéne menni a boltba birkaveséért, megszárítani, porrá törni, és beszórni vele a szervert. Ez segített, mert hirtelen elkezdett esni a delivery latency. Úgy látszik, hogy a filterezés tényleg kikészítette öreg barátunkat.
Hepiend.

(a történeti hűség és politikai korrektség jegyében meg kell mondanom, hogy ez a szerver egy muzeális darab, még SQL 2000-et futtat)

Notification failed SQL Agent jobokra

Lusta embernek tartom magam (azért dolgozom sokat, hogy később ne kelljen, csak ez soha nem jön be), úgyhogy amikor szembesültem azzal, hogy az egyik SQL szerveremen van egy csomó job, aminél nincsen beállítva a figyelmeztetés, ha elbuktak, kitaláltam, hogy scriptből közelítem meg. Miután a msdb.sysjobs táblában nem találtam meg megnyugtató bizonyossággal mindazt, ami kell nekem, elővettem a régi trükköt: elindítottam a SQL Profilert, megnéztem, hogy mi a szöszt csinál az Enterprise Manager (ja, történelem előtti idők, van még SQL 2000 a bolygón).
Az eredmény: van egy sp_update_job nevű tárolt eljárás, amit használ a GUI. Én is ezt tettem, és bár nem nagy barátom, mégis a kurzorhoz nyúltam, mert még mindig szimpatikusabb volt, mint a dinamikusan összerakott kveri (azt a kurzornál és a triggernél is kevésbé szeretem). Megírtam a scriptet, működik 2005-ön is, 2008 most nincs a közelemben.

declare crJobs cursor
FOR

select name from msdb..sysjobs
-- where... ha szeretnénk szűrni
declare @job varchar(200)

open crJobs 
fetch next from crJobs into @job
while (@@fetch_status = 0)
BEGIN
PRINT @job + ' is edited'

EXEC msdb.dbo.sp_update_job @job_name=@job, 
		@notify_level_email=2, 
		@notify_level_netsend=2, 
		@notify_level_page=2, 
		@notify_email_operator_name=N'SQL DBA'

fetch next from crJobs into @job
END
close crJobs
deallocate crJobs 

Természetesen a @notify_email_operator_name paramétert a 18. sorban meg kell adjusztálni.

SQL Server uptime

Az uptime egy nagyon kedves és szeretett funkció számomra az operációs rendszerekben, jó látni, hogy mi mióta fut. Az SQL szerver esetében is lehet igény erre a szolgáltatásra, amit nem nehéz megvalósítani, ha egy aprócska tényt kihasználunk.

USE master

CREATE PROCEDURE sp_uptime
AS
DECLARE @up DATETIME
SELECT @up = login_time FROM sys.dm_exec_sessions WHERE session_id = 1

DECLARE @day varchar(4), @hour char(2), @minute varchar(10)
SELECT @minute = DATEDIFF(minute, @up, getdate())
SELECT @day = @minute / 1440, @minute = @minute % 1440, 
		@hour = @minute / 60, @minute = @minute % 60
PRINT @@SERVERNAME + ' has been up for ' + @day + ' day(s), ' + @hour + ' hour(s), ' + @minute + ' minute(s).'

Az alapötlet a hatodik sorban látható: az 1-es SPID-del rendelkező processz, a resource monitor a szerver indulásakor logol be, és ott is marad, amíg fut a SQL. Ezek után némi favágással a dátumot a megszokott uptime küllemre hoztam. A végén a print került be select helyett, mivel így nem kell azon bénázni, hogy az oszlopszélességet állítgassuk (persze aki szereti, írja át bátran). SQL 2000-nél a sys.dm_exec_sessions helyett master..sysprocesses van, session_id helyett pedig spid.
Azért a master adatbázis, mert így akárhol bemondhatjuk, hogy sp_uptime, az le fog futni, mivel az SQL minden sp_ kezdetű tárolt eljárást először a masterban keres, és csak aztán az aktuális adatbázisban. (Ezért nem jó ötlet sp_ kezdetű tárolt eljárásokat csinálni az alkalmazásainkhoz, mert mindig be fog nézni a masterba is a SQL szerver.)
Hogy mire használható? Öööö… fogalmam sincs. Én akkor találtam ki, amikor időnként megszakadt a kapcsolatom a szerverhez, ami amúgy is sztochasztikusan működött, néha újraindult, néha csak az oprendszer tűnt el a hálózatról, és jó volt tudni, hogy éppen hányadán állok a kis döggel.

Szemafor T-SQL-ben

Egy szép napon szembesültem azzal a problémával, hogy alkalmazásszerverek párhuzamos futásuk közben vágják egymás alatt a fát. Az alkalmazások módosítása kicsit fájdalmas lett volna, ezért SQL oldalon kezeltük le a problémát. A kritikus szakaszban egyszerre csak egyvalaki lehet – ezt szokták szemaforral biztosítani. Na, ez történt itt is, csak T-SQL-ben szemaforoztam. Érdekes élmény:

-- SQL 2005 - alapvetően a try-catch-re építünk
WHILE 1 = 1
BEGIN
BEGIN TRY
	CREATE TABLE ##semaphor (a int);
	BREAK;
END TRY
BEGIN CATCH
	WAITFOR DELAY '000:00:03';
	CONTINUE;
END CATCH
END
-- Itt a kritikus szakasz
DROP TABLE ##semaphor

A gondolatmenet egyszerű: van egy globális temptábla (a dupla rácsos linzer jelzi, hogy ezt bárki elérheti, nemcsak a létrehozója), ami a szemafor. Aki létrehozta, az beléphet a kritikus szakaszba, a többiek meg egy helyben ugrálnak, és próbálják létrehozni a táblát. Ennyi.
Felvetődik a kérdés, hogy mi van azzal, aki SQL 2000-t futtat még. Az egyrészt upgrade-elhet :), másrészt pedig használhatja a következő scriptet:

-- SQL 2000-ben az object_id a barátunk
WHILE object_id('tempdb..##semaphor') is not null
BEGIN
WAITFOR DELAY '000:00:03'
END
CREATE TABLE ##semaphor (a int)
-- Itt a kritikus szakasz
DROP TABLE ##semaphor

Mivel a SQL 2000-ben még nincs try-catch, teljesen más logikával kell hozzáállnom: lekérdezem az object_id-ját a temptáblának, ha létezik, akkor várok, ha nem, akkor megcsinálom. Egyetlen gyenge pontja az előzőhöz képest: ha egyszerre ketten látják úgy, hogy nincs ott a temptábla, és megpróbálják létrehozni, akkor az egyik sikerül, a másik pedig elszáll egy szép exception-nel, mert már létezik a tábla. Ezt sajnos nem bírtam lekezelni. Egyébként meglepően gyakran fordul elő ez az eset ahhzo képest, hogy mennyire kicsinek tűnik a valószínűsége.