Category: DBA Utilities

How to identify Restore details in SQL Server

Problem Statement:

Today, one of my colleague was looking for a way to identify the backup file path for one his restored databases. The below script would help you in similar situation.

Script:


DECLARE @dbname sysname, @days int
SET @dbname = NULL --provide database name you want
--number of days since need to check, script will default to 25
SET @days = -25 
SELECT
     rs.destination_database_name AS [Database],
     rs.user_name AS [Restored By],
     CASE WHEN rs.restore_type = 'D' THEN 'Database'
      WHEN rs.restore_type = 'F' THEN 'File'
      WHEN rs.restore_type = 'G' THEN 'Filegroup'
      WHEN rs.restore_type = 'I' THEN 'Differential'
      WHEN rs.restore_type = 'L' THEN 'Log'
      WHEN rs.restore_type = 'V' THEN 'Verifyonly'
      WHEN rs.restore_type = 'R' THEN 'Revert'
     ELSE rs.restore_type 
     END AS [Restore Type],
     rs.restore_date AS [Restore Started],
     bmf.physical_device_name AS [Restored From], 
     rf.destination_phys_name AS [Restored To]
FROM msdb.dbo.restorehistory rs
 INNER JOIN msdb.dbo.backupset bs 
     ON rs.backup_set_id = bs.backup_set_id
 INNER JOIN msdb.dbo.restorefile rf 
     ON rs.restore_history_id = rf.restore_history_id
 INNER JOIN msdb.dbo.backupmediafamily bmf 
     ON bmf.media_set_id = bs.media_set_id
WHERE rs.restore_date >= DATEADD(dd, ISNULL(@days, -30), GETDATE()) 
     AND destination_database_name = ISNULL(@dbname, destination_database_name) 
ORDER BY rs.restore_history_id DESC

TSQL Script to get Backup details in SQL Server

One of my colleague was looking for a script to identify the backup details for one his databases. Here is a very simple script to identify database backup details.

Purposes:

1. To confirm all the backup jobs are running fine at the defined intervals
2. To confirm the necessary backup strategies are in place For ex: For FULL recovery model requires frequent log backups to avoid the space issues
3. To identify the backup startdate and finishdate for backups
4. To identify the device name to which backups are initiated
5. To identify who initiated the backups(username)

SCRIPT


SELECT  
   CONVERT(CHAR(100), SERVERPROPERTY('Servername')) AS Server, 
   BkpSet.server_name,
   BkpSet.database_name, BkpSet.recovery_model,
   BkpSet.backup_start_date, BkpSet.backup_finish_date, 
   BkpSet.expiration_date, 
   CASE BkpSet.type  
       WHEN 'D' THEN 'Database(FULL)' 
       WHEN 'I' THEN 'Differential' 
       WHEN 'L' THEN 'Log'  
   END AS backup_type, BkpSet.backup_size,  
   BkpMF.logical_device_name,  BkpMF.physical_device_name,   
   BkpSet.name AS backupset_name, BkpSet.description, user_name
   FROM   msdb.dbo.backupmediafamily BkpMF
   INNER JOIN msdb.dbo.backupset BkpSet 
           ON BkpMF.media_set_id = BkpSet.media_set_id  
   WHERE  
   (CONVERT(datetime, BkpSet.backup_start_date, 102) >= GETDATE() - 7)  
   ORDER BY BkpSet.backup_finish_date desc

See Also:
Read more on SQL Server Job details:
https://latheeshnk.wordpress.com/2015/04/03/t-sql-script-get-sql-job-details-and-history-details/

Auto File Growth: Track the growth events Using Extended Events in SQL Server

This is a continued blog post for Auto File Growth – Different ways to track the growth events to answer one of the comments.

The author of the comment (Vinuraj R) was looking for a way to capture the Growth events through Extended Events. Let me begin with a Thank you note to the author talking about Extended Events. Extended Events are powerful ways to capture most of the metrics from the SQL Server 2008 own wards.

Here, We are going to see a method to track/cpature the growth of (Data/Log)files using Extended Events.

First of all, we are going to create an EVENT SESSION on the Server to capture the database_file_size_change Event as below: (You may also be able to provide a filter to capture information for any specific database, if required.)


-- Create event
CREATE EVENT SESSION [DB_file_size_changed] ON SERVER 
ADD EVENT sqlserver.database_file_size_change(SET collect_database_name=(1)
    ACTION
   (sqlserver.client_app_name,sqlserver.client_hostname, sqlserver.database_id,sqlserver.session_id,
   sqlserver.session_nt_username,sqlserver.username) 
   /* You can filter the database that needs to be monitored for the auto growth, for which you need to pass the database id for the filter*/
   --WHERE ([database_id]=()) 
   ) 
ADD TARGET package0.event_file
(SET filename=N'C:\temp\DB_file_size_changed.xel')
WITH (MAX_DISPATCH_LATENCY=1 SECONDS)

Once , Event Session has been created, We need to START the EVENT SESSION as below:Please note that you may need CONTROL SERVER permission to Alter/Drop the Event Session.


ALTER EVENT SESSION DB_File_size_Changed 
ON SERVER STATE = START -- START/STOP to start and stop the event session

Once the Event session is started, events will be capturing the Growth information in the file and we would be able to see those information using the below script:

USE [master];
GO
SELECT
        Case when file_type = 'Data file' Then 'Data File Grow' Else File_Type End AS [Event Name]
	   , database_name AS DatabaseName
	   , file_names
	   , size_change_kb
	   , duration
       , client_app_name AS Client_Application
	   , client_hostname
       , session_id AS SessionID
	   , Is_Automatic 
	   , sql_txt
	   , sql_username
       
FROM (
       SELECT
           n.value ('(data[@name="size_change_kb"]/value)[1]', 'int') AS size_change_kb
           , n.value ('(data[@name="database_name"]/value)[1]', 'nvarchar(50)') AS database_name
           , n.value ('(data[@name="duration"]/value)[1]', 'int') AS duration
           , n.value ('(data[@name="file_type"]/text)[1]','nvarchar(50)') AS file_type
           , n.value ('(action[@name="client_app_name"]/value)[1]','nvarchar(50)') AS client_app_name
           , n.value ('(action[@name="session_id"]/value)[1]','nvarchar(50)') AS session_id
		   , n.value ('(action[@name="client_hostname"]/value)[1]','nvarchar(50)') AS Client_HostName
		   , n.value ('(data[@name="file_name"]/value)[1]','nvarchar(50)') AS file_names
		   , n.value ('(data[@name="is_automatic"]/value)[1]','nvarchar(50)') AS Is_Automatic
		   , n.value ('(action[@name="sql_text"]/value)[1]','nvarchar(500)') AS sql_txt
			, n.value ('(action[@name="username"]/value)[1]','nvarchar(50)') AS sql_username
           
       FROM 
           (   SELECT CAST(event_data AS XML) AS event_data
               FROM sys.fn_xe_file_target_read_file(
                   N'C:\temp\DB_file_size_changed*.xel',
                   NULL,
                   NULL,
                   NULL)
           ) AS Event_Data_Table
CROSS APPLY event_data.nodes('event') AS q(n)) xyz
ORDER BY database_name

Here is a sample report generated with my testing.
AutoGrowth_ExtendedEvent

Hope, this post would help to understand another way of capturing File Growth information.

Auto File Growth – Different ways to track the growth events

Auto-Growth events are occurring when the data/log file is trying to expand size due to out of space.The amount that grows, depends on the file growth option provided for the database. Recently, in one of the project, it has been observed that the Auto growth event occurred 4 times for one of data file and a delay in response time.

Whats the problem with Auto Growth?

Auto Growth can not be stopped completely, however, a careful configuration of Growth option can control the number of Auto Growth events.The problem with Auto Growth is that during the growth event, the database would be halted until the growth event has completed. For a higher size, it can take more time there by a huge delay in processing for the request and in turn several performance issues.In addition, when the space is allocating, it may not be a contiguous space resulting a physical fragmentation of the database file on the disk. If the number of Auto Growth is high, then there will be more physical fragmentation.

How do you find the Auto Growth events?

This blog post is neither intended nor explained the cause of the growth or its resolution.Lets us look at it later. Here, We would see some of common methods to identify the Auto Growth events in SQL Server.

–Using default trace

Default trace is a very powerful way of capturing issues in SQL Server. Some of common EventClasses and its description is given below.

/*

EventClass Description
********************************************************

18 -Audit Server Starts And Stops
20 -Audit Login Failed
22 -Error log
46 -Object:Created
47 -Object:Deleted
55 -Hash Warning
69 -Sort Warnings
79 -Missing Column Statistics
80 -Missing Join Predicate
81 -Server Memory Change
92 -Data File Auto-Grow
93 -Log File Auto-Grow

116 -Audit DBCC Event
164 -Object:Altered
175 -Audit Server Alter Trace Event
*/

Now, lets look at the way to capture Auto Growth Event from trace as below.

DECLARE @filename NVARCHAR(1000);

-- Get the name of the current default trace
SELECT @filename = CAST(value AS NVARCHAR(1000))
FROM ::fn_trace_getinfo(DEFAULT)
WHERE traceid = 1 AND property = 2;

--To find the filename without rollover number
SET @filename = REVERSE(@filename);
SET @filename = REVERSE(SUBSTRING(@filename,CHARINDEX('_',@filename)+1,LEN(@filename))) 
					+ REVERSE(SUBSTRING(@filename,1,CHARINDEX('.',@filename)));

-- Get the details
SELECT 
  Trace.StartTime, Trace.EndTime,TraceEvent.name AS EventName,Trace.DatabaseName  
,Trace.Filename,Trace.EventClass,(Trace.IntegerData*8)/1024.0 AS GrowthMB 
,(Trace.duration/1000)AS DurationInMS
FROM ::fn_trace_gettable(@filename, DEFAULT) AS Trace 
INNER JOIN sys.trace_events AS TraceEvent ON Trace.EventClass = TraceEvent.trace_event_id  
WHERE (Trace.EventClass = 92  
    OR Trace.EventClass = 93) 
ORDER BY Trace.StartTime

–Using SQL Error log

SQL Server will provide the Auto Growth events in the Error log as below snapshot. The errorlog information contains the file name and database with the time taken to process the Auto Growth. Note, these are the events 5144 & 5145 logged only when autogrowth takes longer time or times out.

AutoGrowth_ErrorLog

–Using Live monitoring query

Using the script in the post, you would be able to see the wait types like LATCH_EX/PREEMPTIVE_OS_WRITEFILEGATHER occurring in the server along with the resource description as FGCB_ADD_REMOVE(A prominent type of Latch – File Group Control Block Add/Remove), which is an indication for Auto Growth Event.

These are my favorite methods to identify the Auto Growth events. If you have any other ways, I would like to request you to share the information here.

Live Monitoring Queries to troubleshoot issues in SQL Server

Here, I would like to share one of my favorite Live monitoring DMV Scripts.

It contains two sessions as below. This has been very helpful to me while monitoring the SQL Server Production issues on the floor.

1. Identify the requests in the SQL Server those are currently running

SELECT  r.session_id ,Getdate() 'CurrentDateTime',r.blocking_session_id 'Blocking Session ID',
	(Select Top 1 CON.client_net_address From sys.dm_exec_connections AS CON 
	where CON.session_id = r.session_id) Client_Address,
		Coalesce(Quotename(Db_name(qt.dbid)) + N'.' + Quotename(Object_schema_name(qt.objectid, qt.dbid)) + N'.' +      
				Quotename(Object_name(qt.objectid, qt.dbid)), '') AS command_text,
        r.[status] ,
        r.wait_type ,wait_resource,r.wait_time / (1000.0) 'Wait Time (in Sec)',
        r.scheduler_id ,
        SUBSTRING(qt.[text], r.statement_start_offset / 2,
            ( CASE WHEN r.statement_end_offset = -1
                   THEN LEN(CONVERT(NVARCHAR(MAX), qt.[text])) * 2
                   ELSE r.statement_end_offset
              END - r.statement_start_offset ) / 2) AS [statement_executing] ,
        DB_NAME(qt.[dbid]) AS [DatabaseName] ,
        r.cpu_time ,r.total_elapsed_time / (1000.0) 'Elapsed Time (in Sec)',
        r.reads ,r.writes ,r.logical_reads ,
        r.plan_handle,r.sql_handle
        ,s.login_name ,s.host_name ,s.program_name,s.host_process_id ,s.last_request_end_time,s.login_time
FROM    sys.dm_exec_sessions AS s
		INNER JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id
        CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS qt
WHERE   r.session_id > 50

2. Identify relevant information like blocking/wait type/queryplan etc.

SELECT
    [DOWT].[session_id],[DOWT].[exec_context_id],
    [DOWT].[wait_duration_ms],[DOWT].[wait_type],
    [DOWT].[blocking_session_id],[DOWT].[resource_description],
    CASE [DOWT].[wait_type]
        WHEN N'CXPACKET' THEN
            RIGHT ([DOWT].[resource_description],
            CHARINDEX (N'=', REVERSE ([DOWT].[resource_description])) - 1)
        ELSE NULL
    END AS [Node ID],[DES].[program_name],[DEST].text,
    [DER].[database_id],[DEQP].[query_plan],[DER].[cpu_time]
FROM sys.dm_os_waiting_tasks [DOWT]
INNER JOIN sys.dm_exec_sessions [DES] ON
    [DOWT].[session_id] = [DES].[session_id]
INNER JOIN sys.dm_exec_requests [DER] ON
    [DES].[session_id] = [DER].[session_id]
OUTER APPLY sys.dm_exec_sql_text ([DER].[sql_handle]) [DEST]
OUTER APPLY sys.dm_exec_query_plan ([DER].[plan_handle]) [DEQP]
WHERE [DES].[is_user_process] = 1
ORDER BY [DOWT].[session_id], [DOWT].[exec_context_id];

I’d like to grow my readership. If you enjoyed this blog post, please share it with your friends!