Archive for July, 2010
[PL] SQL Server – Kontrola dzienników transakcji
Jul 7th
Jednymi z problemów najczęściej poruszanych na forum poświęconym SQL Serverowi na portalu WSS.pl są wszelkiej maści kłopoty wynikające z zaniedbania dziennika transakcji bazy danych. Rekordziści prześcigają się w wielkości plików dziennika transakcji (185 GB dla bazy kilkugigabajtowej to dobry przykład). Często padają pytania, jak to wszystko (recovery model, dziennik transakcji, backup dziennika transakcji) działa. Nie zamierzam się rozpisywać o podstawach logowania operacji DML czy o tym, jak zbudowany jest dziennik transakcji. Pomyślałem za to, że fajnie byłoby napisać skrypt dla DBA lub konsultanta, dzięki któremu będzie można, wchodząc na “cudzy” (lub, o zgrozo, także swój!) serwer, zdiagnozować podstawowe problemy związane z higieną dziennika transakcji (a w zasadzie z brakiem tej higieny). Wspomniany skrypt prezentuje się tak:
SET NOCOUNT ON;
IF OBJECT_ID('tempdb.dbo.#VLFs', 'U') IS NOT NULL
DROP TABLE #VLFs;
CREATE TABLE #VLFs (
FileId int NULL,
FileSize bigint NULL,
StartOffset bigint NULL,
FSeqNo bigint NULL,
Status tinyint NULL,
Parity smallint NULL,
CreateLSN numeric(25,0) NULL
);
IF OBJECT_ID('tempdb.dbo.#NumberOfVLFs', 'U') IS NOT NULL
DROP TABLE #NumberOfVLFs;
CREATE TABLE #NumberOfVLFs (
DatabaseName sysname NOT NULL,
NumberOfVLFs int NOT NULL
);
DECLARE @DBName sysname, @SQL nvarchar(4000);
DECLARE DBCursor CURSOR LOCAL STATIC
FOR
SELECT name FROM sys.databases WHERE state_desc = 'ONLINE';
OPEN DBCursor;
FETCH NEXT FROM DBCursor INTO @DBName;
WHILE @@FETCH_STATUS = 0 BEGIN
DELETE FROM #VLFs;
SET @SQL =
'INSERT INTO #VLFs
EXEC ' + QUOTENAME(@DBName)
+ '.dbo.sp_executesql N''DBCC LOGINFO WITH NO_INFOMSGS'';
INSERT INTO #NumberOfVLFs (DatabaseName, NumberOfVLFs)
SELECT ' + QUOTENAME(@DBName, '''') + ', COUNT(*)
FROM #VLFs;';
EXEC (@SQL);
FETCH NEXT FROM DBCursor INTO @DBName;
END
CLOSE DBCursor;
DEALLOCATE DBCursor;
IF OBJECT_ID('tempdb.dbo.#LogHealth', 'U') IS NOT NULL
DROP TABLE #LogHealth;
CREATE TABLE #LogHealth (
DatabaseName sysname NULL,
LogSizeMB numeric(38,2) NULL,
LogSpaceUsed numeric(4,2) NULL,
Status tinyint NULL
);
INSERT INTO #LogHealth EXEC ('DBCC SQLPERF(LOGSPACE) WITH NO_INFOMSGS');
SELECT
v.DatabaseName AS [Database name],
d.recovery_model_desc AS [Recovery model],
CASE
WHEN d.recovery_model = 1
AND r.last_log_backup_lsn IS NOT NULL
THEN 1
ELSE 0
END AS [Was backup taken],
q.number_of_files AS [Number of log files],
l.LogSizeMB AS [Log size (MB)],
l.LogSpaceUsed AS [Log space used (%)],
v.NumberOfVLFs AS [Number of VLFs],
d.log_reuse_wait_desc AS [Log reuse wait cause]
FROM #NumberOfVLFs AS v
INNER JOIN #LogHealth AS l
ON v.DatabaseName = l.DatabaseName
INNER JOIN sys.databases AS d
ON v.DatabaseName = d.name
INNER JOIN sys.database_recovery_status AS r
ON d.database_id = r.database_id
INNER JOIN (
SELECT
m.database_id,
COUNT(*) AS number_of_files
FROM sys.master_files AS m
WHERE m.type = 1
GROUP BY m.database_id
) AS q
ON d.database_id = q.database_id;
GO
Wynikiem działania powyższego kodu jest coś takiego:
Co oznaczają kolejne kolumny?
- Database name – nazwa bazy danych (powinny pokazać się wszystkie bazy)
- Recovery model – tryb pracy dziennika transakcji (dla produkcyjnych baz zalecany FULL)
- Was backup taken – wskazuje, czy został wykonany backup rozpoczynający działanie bazy w trybie FULL
- Number of log files – ilość plików dziennika transakcji, w zasadzie zawsze powinien być 1 plik (wyjątkiem są sytuacje, gdy musimy dodać drugi lub kolejny plik dziennika transakcji z uwagi na brak miejsca na dysku przechowującym pierwszy plik dziennika)
- Log size (MB) – rozmiar dziennika transakcji w megabajtach (wiadomo – duży może być zwłaszcza, gdy dziennik transakcji jest zaniedbany)
- Log space used (%) – ile procent dziennika transakcji jest zajęte przez zapisane w nim transakcje (tak dowiemy się, ile brakuje do tego, by dziennik transakcji automatycznie się rozrósł)
- Number of VLFs – ilość wirtualnych plików dziennika transakcji (ang. Virtual Log File); zalecane jest poniżej 50, ale rząd wielkości więcej – 300-500 to też nie jest wielka tragedia; ale jeżeli liczba idzie w dziesiątki / setki tysięcy, można spodziewać się problemów przy starcie bazy oraz dłuższego czasu wykonywania backupów i przywracania bazy
- Log reuse wait cause – informacja na temat przyczyny braku możliwości ponownego zapełniania plików dziennika transakcji od pierwszych plików wirtualnych (najczęściej otwarte transakcje, ale przyczyn może być więcej)
Sam kod wykorzystuje kilka widoków i poleceń DBCC:
- sys.databases – widok systemowy zawierający listę baz danych i ich właściwości
- sys.master_files – widok systemowy zawierający listę plików wszystkich baz danych
- sys.database_recovery_status – widok systemowy zawierający informacje na temat procesów recovery baz danych
- DBCC LOGINFO – nieudokumentowane polecenie DBCC pokazujące układ wirtualnych plików dziennika transakcji dla bieżącej bazy danych (tu użyte do zliczenia wirtualnych plików)
- DBCC SQLPERF(LOGSPACE) – polecenie DBCC zwracające listę baz danych wraz z wielkością dzienników transakcji oraz stopnia wypełnienia tych dzienników
Mam nadzieję, że powyższy kod się przyda. Działa na SQL Server 2005 i nowszych. Przy odrobinie wysiłku można kod przerobić, by działał także na wersji 2000.
I na deser kilka odnośników do postów na blogach, które przeczytałem przed przystąpieniem do pisania kodu:
- Mój log jest za duży (mój stary blog)
- New script: is that database REALLY in the FULL recovery mode? (Paul S. Randal)
- 8 Steps to better Transaction Log throughput (Kimberly L. Tripp)
-
Transaction Log VLFs – too many or too few? (Kimberly L. Tripp)
Szczególnie ciekawy jest bug wymieniony na koniec ostatniego z wymienionych postów – polecam do poczytania :-)
[PL] Dobrze być MVP ;-)
Jul 2nd
Firma Microsoft po raz trzeci z rzędu postanowiła wyróżnić mnie tytułem Microsoft Most Valuable Professional (MVP) w kategorii SQL Server. Wczoraj otrzymałem e-mail o mile łechczącej moje ego treści:
Dear Pawel Potasinski,
Congratulations! We are pleased to present you with the 2010 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in SQL Server technical communities during the past year. (…)
Nie powiem, satysfakcja duża. I choć przecież nie dla nagród obracałem się przez ostatni rok w społeczności IT, to miło być wyróżnionym przez MałegoMiękkiego ;-) Nie zamierzam pisać, czym jest tytuł / program MVP, bo na ten temat już kiedyś pisałem. Korporacja postanowi kogoś wyróżnić i to robi.
W tym miejscu gratulacje należą się szczególnie nominowanym: Tobiaszowi Koprowskiemu (SQL Server) i Kubie Skałbania (Dynamics CRM). A że znam obu Panów, tym większe gratulacje. Gratulacje także dla pozostałych renominowanych:
Niezła paka :-) Niech nikt nie myśli, że renominacje jest łatwo otrzymać! Za każdym razem jesteśmy nagradzani wyłącznie za nasze działania na rzecz społeczności IT w ostatnich 12 miesiącach. A więc każda renominacja to satysfakcja prawie taka, jak za pierwszym razem ;-) (choć oczywiście za pierwszym razem wyróżnienie smakuje ciut inaczej)
W każdym razie, dobrze być znowu MVP ;-)
O programie MVP oraz o osobach wyróżnionych tytułem MVP w Polsce, czytaj na http://mvp.pl.


Nazywam się Paweł Potasiński i pracuję w polskim oddziale Microsoft w dziale Small and Midmarket Solutions & Partners (SMS&P) jako Partner Technology Advisor.




