Facing a deadlock in SQL server database and can see deadlock entry in SQL logs. How the log entries can be used to find the reason for this deadlock?
Deadlock information is captured by the system_health Extended Events trace by default. No need to turn on additional trace flags.
Information from the xml_deadlock event can be viewed from SSMS Object Explorer (Management-->Extended Events-->Sessions--system_health) or with T-SQL. Below is an example query to get the deadlock xml from the file target. You can also save the deadlock xml to a file with an xdl extension and open the file in SSMS for a graphical view of the deadlock.
--get xml_deadlock_report from system_health session file target
WITH
--get full path to current system_health trace file
CurrentSystemHealthTraceFile AS (
SELECT CAST(target_data AS xml).value('(/EventFileTarget/File/#name)[1]', 'varchar(255)') AS FileName
FROM sys.dm_xe_session_targets
WHERE
target_name = 'event_file'
AND CAST(target_data AS xml).value('(/EventFileTarget/File/#name)[1]', 'varchar(255)') LIKE '%\system[_]health%'
)
--get trace folder name and add base name of system_health trace file with wildcard
, BaseSystemHealthFileName AS (
SELECT
REVERSE(SUBSTRING(REVERSE(FileName), CHARINDEX(N'\', REVERSE(FileName)), 255)) + N'system_health*.xel' AS FileNamePattern
FROM CurrentSystemHealthTraceFile
)
--get xml_deadlock_report events from all system_health trace files
, DeadLockReports AS (
SELECT CAST(event_data AS xml) AS event_data
FROM BaseSystemHealthFileName
CROSS APPLY sys.fn_xe_file_target_read_file ( FileNamePattern, NULL, NULL, NULL) AS xed
WHERE xed.object_name like 'xml_deadlock_report'
)
--display 10 most recent deadlocks
SELECT TOP 10
DATEADD(hour, DATEDIFF(hour, SYSUTCDATETIME(), SYSDATETIME()), event_data.value('(/event/#timestamp)[1]', 'datetime2')) AS LocalTime
, event_data AS DeadlockReport
FROM DeadLockReports
ORDER BY LocalTime ASC;
Deadlock information can be captured in the SQL Server Error Log or by using Profiler / Server Side Trace.
1204 - this provides information about the nodes involved in the
deadlock
1222 - returns deadlock information in an XML format
You can turn on each of these separately or turn them on together.
To turn these on you can issue the following commands in a query window or you can add these as startup parameters. If these are turned on from a query window, the next time SQL Server starts these trace flags will not be active, so if you always want to capture this data the startup parameters is the best option.
DBCC TRACEON (1204, -1)
DBCC TRACEON (1222, -1)
Please refer to the following Links for more details
Redgate
MS SQL Tips
This code will display the error log which contains the query that creates the deadlock.
IF OBJECT_ID('tempdb.dbo.ErrorLog') IS Not Null
BEGIN
DROP TABLE tempdb.dbo.ErrorLog
END
CREATE TABLE tempdb.dbo.ErrorLog
(Id int IDENTITY (1, 1) NOT NULL,
logdate DATETIME, procInfo VARCHAR(10),
ERRORLOG VARCHAR(MAX))
-- insert the actual data from the Error log into our newly created table.
INSERT INTO tempdb.dbo.ErrorLog
EXEC master.dbo.sp_readerrorlog
declare #sql nvarchar(max)
set #sql='select logdate, procInfo, ERRORLOG from tempdb.dbo.ErrorLog
where Id >= (select top 1 id from tempdb.dbo.ErrorLog WHERE ERRORLOG Like
''%deadlock-list%'' order by id desc)'
select #SQL
Related
I have some mysterious problem where every day one table in DB (SQL Server 2016) is being recreated (I suppose dropped and created) with old data. I checked various options to try to find what process is doing this, however was unable to do that.
Scheduled Tasks - nothing
SQL Agent Jobs - nothing
How to trace what user/application/anythingelse is doing this ?
I tried launching SQL Profiler and starting manual trace, but after some time (half a day or so) it just stopped.
The default trace captures schema changes. Review the Schema Change History report or run the query below to retrieve the info in T-SQL. Note that the default trace rollover files are limited to 5 files of up to 20MB each so older events may have rolled off.
--select object created and deleted information from default trace
SELECT
trace_table.StartTime
, te.name
, trace_table.ObjectName
, trace_table.ApplicationName
, trace_table.LoginName
FROM (
SELECT REVERSE(SUBSTRING(REVERSE(path), CHARINDEX('\', REVERSE(path)) , 255)) + 'log.trc'
FROM sys.traces
WHERE
is_default = 1
) AS trace(path)
CROSS APPLY sys.fn_trace_gettable(trace.path, DEFAULT) AS trace_table
JOIN sys.trace_events AS te ON
te.trace_event_id = trace_table.EventClass
WHERE
EventSubClass = 0
AND name IN('Object:Created', 'Object:Deleted')
ORDER BY StartTime;
create a database trigger and log the create/drop table events:
create table dbo.traceTabledropcreate(EventDataXML xml, LogDatetime datetime default(getdate()));
go
create or alter trigger dbtrigger_traceTabledropcreate
on database
with execute as 'dbo'
for CREATE_TABLE, DROP_TABLE
as
begin
set nocount on;
--insert into dbo.traceTabledropcreate(EventDataXML)
--values (EVENTDATA());
declare #sessionxml xml =
(
select EVENTDATA(),
(
select *
from sys.dm_exec_sessions
where session_id = ##spid
for xml path('sessioninfo'), type
)
for xml path('')
);
insert into dbo.traceTabledropcreate(EventDataXML)
values (#sessionxml);
end
go
---..... and wait....
--..test
create table dbo.testtable(id int)
go
select *
from dbo.traceTabledropcreate
go
drop table dbo.testtable
go
select *
from dbo.traceTabledropcreate
go
For 6 months I had linked servers working properly in SQL Server. Everything worked fine, but something strange started to happen. A week ago I was notified that synchronization was not working. I discovered that the linked servers have disappeared. I added them again but after 3 days again but after 3 days they disappeared again.
I didn't delete them manually.
Is it possible that something removed them?
How to protect against automatic removal?
Windows Server 2019, SQL Server 2017
Create a table that will hold tracked operations, something like:
CREATE TABLE EventLogTable (
EventLogTableID INT IDENTITY PRIMARY KEY,
EventType NVARCHAR(100),
PostTime DATETIME,
SPID INT,
ServerName NVARCHAR(100),
LoginName NVARCHAR(100),
ObjectName NVARCHAR(100),
ObjectType NVARCHAR(100),
[Parameters] NVARCHAR(1000),
TargetObjectName NVARCHAR(100),
TargetObjectType NVARCHAR(100),
TSQLCommand NVARCHAR(1000))
Then create a DDL server trigger that monitors linked server events, through the EVENTDATA() function:
CREATE TRIGGER utrLogLinkedServerOperations ON ALL SERVER FOR
CREATE_LINKED_SERVER,
DROP_LINKED_SERVER,
ALTER_LINKED_SERVER
AS
BEGIN
DECLARE #EventXML XML = EVENTDATA()
INSERT INTO EventLogTable (
EventType,
PostTime,
SPID,
ServerName,
LoginName,
ObjectName,
ObjectType,
[Parameters],
TargetObjectName,
TargetObjectType,
TSQLCommand)
SELECT
EventType = #EventXML.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(100)'),
PostTime = #EventXML.value('(/EVENT_INSTANCE/PostTime)[1]', 'nvarchar(100)'),
SPID = #EventXML.value('(/EVENT_INSTANCE/SPID)[1]', 'nvarchar(100)'),
ServerName = #EventXML.value('(/EVENT_INSTANCE/ServerName)[1]', 'nvarchar(100)'),
LoginName = #EventXML.value('(/EVENT_INSTANCE/LoginName)[1]', 'nvarchar(100)'),
ObjectName = #EventXML.value('(/EVENT_INSTANCE/ObjectName)[1]', 'nvarchar(100)'),
ObjectType = #EventXML.value('(/EVENT_INSTANCE/ObjectType)[1]', 'nvarchar(100)'),
[Parameters] = #EventXML.value('(/EVENT_INSTANCE/Parameters)[1]', 'NVARCHAR(1000)'),
TargetObjectName = #EventXML.value('(/EVENT_INSTANCE/TargetObjectName)[1]','nvarchar(100)'),
TargetObjectType = #EventXML.value('(/EVENT_INSTANCE/TargetObjectType)[1]', 'nvarchar(100)'),
TSQLCommand = #EventXML.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'NVARCHAR(1000)')
END
You can find the XML schema in here. Make sure to enable the trigger:
ENABLE TRIGGER utrLogLinkedServerOperations ON ALL SERVER
Now try creating, modifying and dropping a few linked servers to check that the trigger is correctly creating the log in the table. Then wait for the ninja to attack.
You could also rollback the operation inside the trigger but beware, you might end up not allowing even desired processes to manipulate linked servers.
Dropping linked server requires ALTER ANY LINKED SERVER permission.
To find out who could do it you should find who has this permission at the server level (my second query that searches in sys.server_permissions). It's rare that someone has this permission granted explicitly, so you should search among sysadmins and setupadmins too.
I also include principals that have control server permission to my search.
Note that even if you can set up DDL-trigger someone with control server or just sysadmin can easily disable it when he wants to drop linked servers and not be captured.
select sp.name as RoleName,
member.name as MemberName
from sys.server_role_members rm
join sys.server_principals as sp
on rm.role_principal_id = sp.principal_id
join sys.server_principals as member
on rm.member_principal_id = member.principal_id
where sp.name in ('sysadmin', 'setupadmin');
select suser_name(grantee_principal_id), permission_name
from sys.server_permissions
where permission_name in ('ALTER ANY LINKED SERVER', 'CONTROL SERVER');
This is my first foray into the world of StackOverflow, so hopefully I provide you with enough information here.
I'm an intern at my company and the boss has assigned me the task of investigating whether or not System Center Operations Manager (SCOM) can monitor for a SQL Server stack dump. Is this possible?
I was thinking of using a query to raise some sort of event in the Windows Application log. Then I could have SCOM monitor the Windows App log for stack dumps and then raise an alarm. Here is the query:
--To view SQL Server error logs in SQL Server 2005 / 2008 / 2008R2
DECLARE #HOURS INT
SET #HOURS = 24
CREATE TABLE #ErrorLog
(LogDate DateTime, ProcessInfo Varchar(50),
[Text] Varchar(4000))
INSERT INTO #ErrorLog
EXEC sp_readerrorlog
DELETE FROM #ErrorLog
WHERE LogDate < CAST(DATEADD(HH,-#HOURS,
GETDATE()) AS VARCHAR(23))
SELECT * FROM #ErrorLog
DROP TABLE #ErrorLog
I know this query won't do what I want it to, but maybe it's a starting point.
CREATE TABLE #names (
[name] nvarchar(max)
);
INSERT INTO #names ([name])
SELECT CustomerName from CustomerInformation
Where status=3
Will the INSERT INTO #names... show up in a SQL Server trace as an INSERT to a table in tempdb or a select from CustomerInformation. Or will both show up in the trace?
Basically, will the trace show the statement as a insert or a select?
Depends what event you're actually looking for in the Trace:
SQL:StmtCompleted and SP:StmtCompleted will show the statement that executed: INSERT INTO ... SELECT FROM ...
SQL:BatchCompleted will show the complete SQL batch (request) that executed: CREATE TABLE ...; INSERT INTO ... SELECT FROM ....
Other events enabled in the Trace will show up accordingly (locks, security audits, query plans etc etc). But the gist of your question is: INSERT INTO ... SELECT ... FROM ... is one single statement, not two statements.
Your statement will appear in the trace once, exactly as you enter it. The database associated with the statement will be the current database when the command is executed. Since you don't specify a database in the FROM clause, the current database will be the database where the CustomerInformation table resides.
I've used the SQL Profiler to generate a trace file, and tuning advisor to take that trace file and provide some recommendations on db updates.
However, the SQL Profiler doesn't seem to track the queries when running against a Reporting Server, the profiler doesn't seem to be capturing any of the queries. I'm logging the defaults (SQL:BatchCompleted and Starting, RPC:completed, and Sessions - Existing Connections)
What events should I be capturing in SQL Profiler in order to run the tuning advisor?
Update:
The BatchStarting even is capturing some SQL; however it's always something to do with the event or notifications table :
declare #BatchID uniqueidentifier
set #BatchID = NEWID()
UPDATE [Event] WITH (TABLOCKX)
SET [BatchID] = #BatchID,
[ProcessStart] = GETUTCDATE(),
[ProcessHeartbeat] = GETUTCDATE()
FROM (
SELECT TOP 8 [EventID] FROM [Event] WITH (TABLOCKX) WHERE [ProcessStart] is NULL ORDER BY [TimeEntered]
) AS t1
WHERE [Event].[EventID] = t1.[EventID]
select top 8
E.[EventID],
E.[EventType],
E.[EventData]
from
[Event] E WITH (TABLOCKX)
where
[BatchID] = #BatchID
ORDER BY [TimeEntered]
Here's what was happening, and how to work around it.
It appears that Reporting Server caches data in a temp database. Since most of our reports all used a common view, all of that data was being retrieved from cache.
After selected "Show All Events", under "Stored Procedures" I selected CacheHit, CacheInert, CacheMiss, Completed, StmtCompleted, and StmtStarting.
There was then enough information in the trace file for the profiler to evaluate and make recommendations.