How can I query how much time a SQL server database restore takes? - sql-server

Im trying to write a query that will tell me how much time a restore (full or log) has taken on SQL server 2008.
I can run this query to find out how much time the backup took:
select database_name,
[uncompressed_size] = backup_size/1024/1024,
[compressed_size] = compressed_backup_size/1024/1024,
backup_start_date,
backup_finish_date,
datediff(s,backup_start_date,backup_finish_date) as [TimeTaken(s)],
from msdb..backupset b
where type = 'L' -- for log backups
order by b.backup_start_date desc
This query will tell me what is restored but now how much time it took:
select * from msdb..restorehistory
restorehistory has a column backup_set_id which will link to msdb..backupset, but that hold the start and end date for the backup not the restore.
Any idea where to query the start and end time for restores?

To find the RESTORE DATABASE time, I have found that you can use this query:
declare #filepath nvarchar(1000)
SELECT #filepath = cast(value as nvarchar(1000)) FROM [fn_trace_getinfo](NULL)
WHERE [property] = 2 and traceid=1
SELECT *
FROM [fn_trace_gettable](#filepath, DEFAULT)
WHERE TextData LIKE 'RESTORE DATABASE%'
ORDER BY StartTime DESC;
The downside is, you'll notice that, at least on my test server, the EndTime is always NULL.
So, I came up with a second query to try and determine the end time. First of all, I apologize that this is pretty ugly and nested like crazy.
The query below assumes the following:
When a restore is run, for that DatabaseID and ClientProcessID, the next EventSequence contains the TransactionID we need.
I then go and find the max EventSequence for the Transaction
Finally, I select the record that contains RESTORE DATABASE and the maximum transaction associated with that record.
I'm sure someone can probably take what I've done and refine it, but this appears to work on my test environment:
declare #filepath nvarchar(1000)
SELECT #filepath = cast(value as nvarchar(1000)) FROM [fn_trace_getinfo](NULL)
WHERE [property] = 2 and traceid=1
SELECT *
FROM [fn_trace_gettable](#filepath, DEFAULT) F5
INNER JOIN
(
SELECT F4.EventSequence MainSequence,
MAX(F3.EventSequence) MaxEventSequence, F3.TransactionID
FROM [fn_trace_gettable](#filepath, DEFAULT) F3
INNER JOIN
(
SELECT F2.EventSequence, MIN(TransactionID) as TransactionID
FROM [fn_trace_gettable](#filepath, DEFAULT) F1
INNER JOIN
(
SELECT DatabaseID, SPID, StartTime, ClientProcessID, EventSequence
FROM [fn_trace_gettable](#filepath, DEFAULT)
WHERE TextData LIKE 'RESTORE DATABASE%'
) F2 ON F1.DatabaseID = F2.DatabaseID AND F1.SPID = F2.SPID
AND F1.ClientProcessID = F2.ClientProcessID
AND F1.StartTime > F2.StartTime
GROUP BY F2.EventSequence
) F4 ON F3.TransactionID = F4.TransactionID
GROUP BY F3.TransactionID, F4.EventSequence
) F6 ON F5.EventSequence = F6.MainSequence
OR F5.EventSequence = F6.MaxEventSequence
ORDER BY F5.StartTime
EDIT
I made some changes to the query, since one of the test databases I used is case-sensitive and it was losing some records. I also noticed when restoring from disk that the DatabaseID is null, so I'm handling that now as well:
SELECT *
FROM [fn_trace_gettable](#filepath, DEFAULT) F5
INNER JOIN
(
SELECT F4.EventSequence MainSequence,
MAX(F3.EventSequence) MaxEventSequence, F3.TransactionID
FROM [fn_trace_gettable](#filepath, DEFAULT) F3
INNER JOIN
(
SELECT F2.EventSequence, MIN(TransactionID) as TransactionID
FROM [fn_trace_gettable](#filepath, DEFAULT) F1
INNER JOIN
(
SELECT DatabaseID, SPID, StartTime, ClientProcessID, EventSequence
FROM [fn_trace_gettable](#filepath, DEFAULT)
WHERE upper(convert(nvarchar(max), TextData))
LIKE 'RESTORE DATABASE%'
) F2 ON (F1.DatabaseID = F2.DatabaseID OR F2.DatabaseID IS NULL)
AND F1.SPID = F2.SPID
AND F1.ClientProcessID = F2.ClientProcessID
AND F1.StartTime > F2.StartTime
GROUP BY F2.EventSequence
) F4 ON F3.TransactionID = F4.TransactionID
GROUP BY F3.TransactionID, F4.EventSequence
) F6 ON F5.EventSequence = F6.MainSequence
OR F5.EventSequence = F6.MaxEventSequence
ORDER BY F5.StartTime

Make it a Job. Then run it as the Job. Then check the View Job History. Then look at the duration column.

While it is running you can check something like this dmv.
select
d.name
,percent_complete
,dateadd(second,estimated_completion_time/1000, getdate())
, Getdate() as now
,datediff(minute, start_time
, getdate()) as running
, estimated_completion_time/1000/60 as togo
,start_time
, command
from sys.dm_exec_requests req
inner join sys.sysdatabases d on d.dbid = req.database_id
where
req.command LIKE '%RESTORE%'
Or you can use some magic voodoo and interpret the transaction log in the following table function, however the only person I know to understand any info in this log is Paul Randal.
I Know he sometimes checks Server Fault, but don't know if he wonders StackOverflow.
select * from fn_dblog(NULL,NULL)
Hope this helps.
If you manage to use this and find a solution please tell us.
Good Luck!

Related

SymmetricDS Tables not syncing

I took over a project that uses SymmetricDs to sync tables between a target and a source. The tables from the source aren't syncing to the target at the moment.
I have searched online but found no help.
I have checked the sym_outgoing_batch and sym_incoming_batch tables but can't figure out the use of the information there.
I also queried the sync_trigger table. I have the result of the query as a link below.
If you have an idea on where I could look, please let me know. I can run queries and give you the result.sync_trigger result
Uncomment these lines "--where status != 'OK'" to see if anything is NOT in OK state if there is that is causing the SYNC to STOP
-- SQL QUERY
-- Symmetric DS : MONITOR : HEARTBEAT / INCOMING / OUTGOING / MONITOREVENTS
SELECT node_id, host_name, getdate() as dtNOW ,heartbeat_time FROM [tablename].[dbo].[sd_node_host] with (NOLOCK) where heartbeat_time > '2022-01-01'
--SELECT * FROM [tablename].[dbo].[sd_context] with (NOLOCK)
SELECT * FROM [tablename].[dbo].[sd_outgoing_batch] with (NOLOCK)
--where status != 'OK'
order by create_time desc
SELECT * FROM [tablename].[dbo].[sd_incoming_batch] with (NOLOCK)
--where status != 'OK'
order by create_time desc
-- Symmetric DS : MONITOR
SELECT * FROM [tablename].[dbo].[sd_monitor_event] with (NOLOCK) WHERE is_resolved != 1
SELECT * FROM [tablename].[dbo].[sd_monitor_event] with (NOLOCK)
EDIT
here is the link for the symmetricds user guide.
https://www.symmetricds.org/doc/3.13/html/user-guide.html#_outgoing_batch
basically NE means it is ready for replication. Did you ever have it set up or is this a new setup that you are trying to get started?
EDIT 2 ENGINE CONFIGS
MAIN
engine.name=<SDS_MAIN>
db.driver=net.sourceforge.jtds.jdbc.Driver
db.url=jdbc:jtds:sqlserver://<IP>:1433/<DB>;useCursors=true;bufferMaxMemory=10240;lobBuffer=5242880
db.user=***********
db.password=***********
registration.url=
sync.url=ttp://<IP>:<PORT>/sync/<SDS_MAIN>
group.id=<GID>
external.id=000
auto.registration=true
initial.load.create.first=true
sync.table.prefix=sym
#start.initial.load.extract.job=false
compression.level=-1
compression.strategy=0
CHILD
engine.name=<SDS_CHILD>
db.driver=net.sourceforge.jtds.jdbc.Driver
db.url=jdbc:jtds:sqlserver://<IP>:1433/<DB>;useCursors=true;bufferMaxMemory=10240;lobBuffer=5242880
db.user=***********
db.password=***********
registration.url=http://<IP>:<PORT>/sync/<SDS_MAIN>
sync.url=http://<IP>:<PORT>/sync/<SDS_CHILD>
group.id=<GID>
external.id=100
auto.registration=true
initial.load.create.first=true
sync.table.prefix=sym
start.initial.load.extract.job=false
compression.level=-1
compression.strategy=0

Who (Or What) ran this query ID

I'd like to know who (Service account, user account ,etc ) ran each query_id that Query_Store records. Is there a way to do this? I've looked all over and can't seem to find anything.
Basically I'd like the data from this to be stored as well. Hostname, and Login Name are very useful to me.
SELECT sdest.DatabaseName
,sdes.session_id
,sdes.[host_name]
,sdes.[program_name]
,sdes.client_interface_name
,sdes.login_name
,sdes.login_time
,sdes.nt_domain
,sdes.nt_user_name
,sdec.client_net_address
,sdec.local_net_address
,sdest.ObjName
,sdest.Query
FROM sys.dm_exec_sessions AS sdes
INNER JOIN sys.dm_exec_connections AS sdec ON sdec.session_id = sdes.session_id
CROSS APPLY (
SELECT db_name(dbid) AS DatabaseName
,object_id(objectid) AS ObjName
,ISNULL((
SELECT TEXT AS [processing-instruction(definition)]
FROM sys.dm_exec_sql_text(sdec.most_recent_sql_handle)
FOR XML PATH('')
,TYPE
), '') AS Query
FROM sys.dm_exec_sql_text(sdec.most_recent_sql_handle)
) sdest
where sdes.session_id <> ##SPID
--and sdes.nt_user_name = '' -- Put the username here !
ORDER BY sdec.session_id
Credit: Execution datetime for SQL queries against SQL Server
There's no DMV that records which sessions ran which queries. To gather that information you must use an Extended Events trace, or a Database Audit.

Find out when the last failover occurred in AlwaysOn availability groups

I used below metioned query to find out if any failover happened in the last 30 minutes
create table #errormsg(duration datetime,errornum int,dbmessage varchar(max))
DECLARE #tags3 VARCHAR(5000)SET #tags3 = (SELECT CAST( t.target_data AS XML ).value('(EventFileTarget/File/#name)[1]', 'VARCHAR(MAX)') FROM sys.dm_xe_sessions s INNER JOIN sys.dm_xe_session_targets t ON s.address = t.event_session_address WHERE t.target_name = 'event_file' and s.name='AlwaysOn_health');
IF #tags3 is Not NULL begin WITH cte_HADR AS (SELECT object_name, CONVERT(XML, event_data) AS data FROM sys.fn_xe_file_target_read_file(#tags3, null, null, null)WHERE object_name = 'error_reported')
insert into #errormsg SELECT data.value('(/event/#timestamp)[1]','datetime')AS [timestamp],data.value('(/event/data[#name=''error_number''])[1]','int') AS [error_number],data.value('(/event/data[#name=''message''])[1]','varchar(max)') AS [message] FROM cte_HADR WHERE data.value('(/event/data[#name=''error_number''])[1]','int') = 1480 select distinct GETDATE() as currenttime, er.duration,dbs.name from #errormsg er inner join sys.databases dbs on er.dbmessage LIKE '%"' +dbs.name+'"%' where er.duration>=(DATEADD(mi,-30,GETDATE()) );
drop table #errormsg;end
else IF OBJECT_ID(N'TempDB.dbo.#errormsg', N'U') IS NOT NULL drop table #errormsg;
But I did not get the result I was expecting because of the "Incorrect Timestamp on Events in Extended Events".
In SSMS -->Management-->Extended Events-->Sessions-->AlwaysOn_health--> click event file.
In that event file,
I checked recently role changed time for 'availablity_replica_state_change'.
In MSSQL log folder--> availablity_replica_state_change time in "AlwaysOn_health" file
timestamp in (1) and (2) needs to be same.
But for me its shows different time. So I didn't get the proper result.
Instead of using extended events, Is there any query to read the MS SQL error logs?
Is there any query to find out if any failover happened in the last 30 minutes?
Please help me to find a solution for this .

Why SQL SERVER 2008 Suddenly change to SINGLE USER from MULTI USER

My production database suddenly changed to single user model.
I changed it back to MULTI USER and now everything is running normally.
Why did this happen?
A database doesn't just get set to single user by itself, there should be some process or person actually issued the command to happened the same.
That ALTER DATABASE command counts as a DDL operation, and it thus logged in the Default Trace.
you can see some quick investigation info from the Schema Changes history Report, or query the default trace directly:
--SELECT * from sys.traces
declare #TraceIDToReview int
declare #path varchar(255)
SET #TraceIDToReview = 1 --this is the trace you want to review!
SELECT #path = path from sys.traces WHERE id = #TraceIDToReview
SELECT
TE.name As EventClassDescrip,
v.subclass_name As EventSubClassDescrip,
T.*
FROM ::fn_trace_gettable(#path, default) T
LEFT OUTER JOIN sys.trace_events TE ON T.EventClass = TE.trace_event_id
LEFT OUTER JOIN sys.trace_subclass_values V
ON T.EventClass = V.trace_event_id AND T.EventSubClass = V.subclass_value
WHERE DatabaseName ='Blank'
AND IndexID = 15 --Single User
OR IndexID = 16 --Multi User

Using T-SQL find the Stored Procedure associated to an SSRS Report

I had some help writing this query -- I'm at a bit of a loss because i'm trying to find the the query type or procedure used and i'm not sure what else to add to the query or how to change it.
SELECT
Ds.Name as Data_Source_Name,
C2.Name AS Data_Source_Reference_Name,
C.Name AS Dependent_Item_Name,
C.Path AS Dependent_Item_Path,
ds.*
FROM
ReportServer.dbo.DataSource AS DS
INNER JOIN
ReportServer.dbo.Catalog AS C ON DS.ItemID = C.ItemID
AND DS.Link IN (SELECT ItemID
FROM ReportServer.dbo.Catalog
WHERE Type = 5) --Type 5 identifies data sources
FULL OUTER JOIN
ReportServer.dbo.Catalog C2 ON DS.Link = C2.ItemID
WHERE
C2.Type = 5
AND c.name LIKE '%mkt%'
ORDER BY
C.Path, C2.Name ASC, C.Name ASC;
Please advise.
Based on my comment, give this a try, should get you moving in the right direction on how you can parse the xml and zero in on the specific command.
You might have to update the name spaces in the script below and also add your report name.
But try something like this:
;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition') --You may have to change this based on you SSRS version
SELECT
[Path],
Name,
report_xml.value( '(/Report/DataSources/DataSource/#Name)[1]', 'VARCHAR(50)' ) AS DataSource,
report_xml.value( '(/Report/DataSets/DataSet/Query/CommandText/text())[1]', 'VARCHAR(MAX)' ) AS CommandText,
report_xml.value( '(/Report/DataSets/DataSet/Query/CommandType/text())[1]', 'VARCHAR(100)' ) AS CommandType,
report_xml
FROM
(
SELECT
[Path],
Name,
[Type],
CAST( CAST( content AS VARBINARY(MAX) ) AS XML ) report_xml
FROM dbo.[Catalog]
WHERE Content IS NOT NULL
AND [Type] = 2
) x
WHERE
--use below in where clause if searching for the CommandText. Depending on how the report was developed I would just use the proc name and no brackets or schema.
--Example: if you report was developed as having [dbo].[procName] just use LIKE '%procName%' below. Because other reports could just have dbo.procName.
report_xml.value( '(/Report/DataSets/DataSet/Query/CommandText/text())[1]', 'VARCHAR(MAX)' ) LIKE '%Your Proc Name here%'
--comment out the above and uncomment below if know your report name and want to search for that specific report.
--[x].[Name] = 'The Name Of Your Report'
You're in the right neighborhood... When a report RDL is published its XML is converted into a image data type and stored in dbo.Catalog.Content.
If you convert the image data to VARBINARY(MAX) and then convert to XML, you'll be able to read the XML in plain text.
SELECT TOP (10)
*
FROM
dbo.Catalog c
CROSS APPLY ( VALUES (CONVERT(XML, CONVERT(VARBINARY(MAX), c.Content))) ) cx (content_xml)
WHERE
c.Type = 2;
From there it's just a matter of parsing the XML to dig out what you're looking for. In this case you looking for tags that look like the following...
<DataSet Name="My_stored_proc">
Are you looking for the stored procedure name? If your looking to see where that is at its in the database itself, database > DatabaseName > Programmability > Stored Procedures. If your trying to use the query you built for a report you need to make the stored procedure or change the query type to text and paste it in the box.

Resources