How to check active transactions in SQL Server 2014? - sql

I am using SQL Server 2014 and want to know how to check my active transactions?

Query with sys.sysprocesses
SELECT * FROM sys.sysprocesses WHERE open_tran = 1
DBCC OPENTRAN : helps to identify active transactions that may be preventing log truncation. DBCC OPENTRAN displays information about the oldest active transaction and the oldest distributed and nondistributed replicated transactions, if any, within the transaction log of the specified database. Results are displayed only if there is an active transaction that exists in the log or if the database contains replication information. An informational message is displayed if there are no active transactions in the log.
sys.dm_tran_active_transactions
Returns information about transactions for the instance of SQL Server.
Syntax
Wondering about Transaction ?
A transaction is a single unit of work. If a transaction is
successful, all of the data modifications made during the transaction
are committed and become a permanent part of the database.
Find more at docs

If you want to know more details about active sessions like
session ID, Host Name,Login Name,Transaction ID,Transaction Name,Trnasaction Begin Time,Databse ID,Database Name you can use below sql query
SELECT
trans.session_id AS [SESSION ID],
ESes.host_name AS [HOST NAME],login_name AS [Login NAME],
trans.transaction_id AS [TRANSACTION ID],
tas.name AS [TRANSACTION NAME],tas.transaction_begin_time AS [TRANSACTION
BEGIN TIME],
tds.database_id AS [DATABASE ID],DBs.name AS [DATABASE NAME]
FROM sys.dm_tran_active_transactions tas
JOIN sys.dm_tran_session_transactions trans
ON (trans.transaction_id=tas.transaction_id)
LEFT OUTER JOIN sys.dm_tran_database_transactions tds
ON (tas.transaction_id = tds.transaction_id )
LEFT OUTER JOIN sys.databases AS DBs
ON tds.database_id = DBs.database_id
LEFT OUTER JOIN sys.dm_exec_sessions AS ESes
ON trans.session_id = ESes.session_id
WHERE ESes.session_id IS NOT NULL
and you will get the result something like

Translation the 3. query that Tharif comments.
select transaction_id, name, transaction_begin_time
,case transaction_type
when 1 then '1 = Read/write transaction'
when 2 then '2 = Read-only transaction'
when 3 then '3 = System transaction'
when 4 then '4 = Distributed transaction'
end as transaction_type
,case transaction_state
when 0 then '0 = The transaction has not been completely initialized yet'
when 1 then '1 = The transaction has been initialized but has not started'
when 2 then '2 = The transaction is active'
when 3 then '3 = The transaction has ended. This is used for read-only transactions'
when 4 then '4 = The commit process has been initiated on the distributed transaction'
when 5 then '5 = The transaction is in a prepared state and waiting resolution'
when 6 then '6 = The transaction has been committed'
when 7 then '7 = The transaction is being rolled back'
when 8 then '8 = The transaction has been rolled back'
end as transaction_state
,case dtc_state
when 1 then '1 = ACTIVE'
when 2 then '2 = PREPARED'
when 3 then '3 = COMMITTED'
when 4 then '4 = ABORTED'
when 5 then '5 = RECOVERED'
end as dtc_state
,transaction_status, transaction_status2,dtc_status, dtc_isolation_level, filestream_transaction_id
from sys.dm_tran_active_transactions

or use DBCC command
DBCC OPENTRAN

The Most Usefull method is;
DBCC opentran()
When You check, you will get below message;
Oldest active transaction:
SPID (server process ID): 190
UID (user ID) : -1
Name : implicit_transaction
LSN : (500549:37333:1)
Start time : Dec 4 2021 10:36:21:673AM
And if you run DBCC opentran several times and you always get same server process ID then system then A transaction is stuck in the database.
Therefore, it is necessary to first look at the SPID detail with the code below and then kill that SPID process.
exec sp_who2 190
exec sp_lock 190
KILL 190

Related

SQL Server is taking too long to execute for a small table?

I'm trying to remove non-alphanumeric from two columns and output it into a brand new table. I did this last time and it executed in about 30 minutes. The table only contains about 3000 rows and I'm connecting to a remote server, and I'm not sure what is the problem here. Please note that I have no permission to create function nor procedure.
Here is my code:
SELECT
[Customer ID], [Original Product Title], [Original Product Type],
[New_Product_Title], [New_Product_Type]
INTO
Customer_Product_2
FROM
Customer_Product
WHILE ##ROWCOUNT > 0
UPDATE Customer_Product
SET New_Product_Title = REPLACE(New_Product_Title, SUBSTRING(New_Product_Title, PATINDEX('%[^a-z0-9]%', New_Product_Title), 1), ''),
New_Product_Type = REPLACE(New_Product_Type, SUBSTRING(New_Product_Type, PATINDEX('%[^a-z0-9]%', New_Product_Type), 1), '')
You don't need the loop since you don't need to check if ##ROWCOUNT > 0 at all. An UPDATE statement will run on the set you give it, if no rows are in the set then no data will be updated.

Establishing business hierarchy in log files – replace CURSOR by something else?

I'm using SQL Server as a warehouse to analyze log files. Those log files carry a kind of bussiness hierarchy (worker in this example):
Log Entry Id, Log Message
1 , Start Worker
2 , Do Cool Stuff
3 , Start Worker
4 , Do further cool stuff
5 , Start Worker
6 , This is a lot of working
7 , End worker
8 , End worker
9 , End worker
I need to relate the log entries to the current worker. The rule is quite simple: once a "Start worker" message is found, assign all following log entries to this worker. In the example hierarchy this means:
Log Entry Id, Log Message , Worker
1 , Start Worker , 1 (we take the entry id as worker id)
2 , Do Cool Stuff , 1
3 , Start Worker , 3
4 , Do further cool stuff , 3
5 , Start Worker , 5
6 , This is a lot of working , 5
7 , End worker , 5
8 , End worker , 3
9 , End worker , 1
Currently I'm using a stored procedure iterating all log entries with a cursor which basically uses a stack to establish the relationship between log entries and workers:
CREATE PROCEDURE CalculateRelations
AS
BEGIN
DECLARE entries_cur CURSOR FOR
SELECT Id, LogMessage
FROM LogEntries
ORDER BY Id;
DECLARE #Id BIGINT;
DECLARE #LogMessage VARCHAR(128);
DECLARE #ParentWorker BIGINT;
DECLARE #WorkerStack VARCHAR(MAX) = '';
OPEN entries_cur;
FETCH NEXT FROM entries_cur INTO #Id, #LogMessage;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC dbo.GetParentWorker #WorkerStack OUT, #Id, #LogMessage, #ParentWorker OUT;
UPDATE LogEntries
SET ParentWorker = #ParentWorker
WHERE Id = #Id;
FETCH NEXT FROM entries_cur INTO #Id, #LogMessage;
END;
CLOSE entries_cur;
DEALLOCATE entries_cur;
END;
GO
GetParentWorker is a stored procedure which uses the given VARCHAR variable WorkerStack as a stack. This means
"Start worker" message leads to adding (push) the Id to that VARCHAR
"End worker" message leads to removing and returning (pop) the last Id from that VARCHAR
all other messages lead to just returning (read) the last Id from that VARCHAR without modifying it
Now I'm wondering if it's possible to replace this cursor construct by a UPDATE statement. I'm not that deep in SQL and SQL Server, but might it be possible to realize this by dynamic variable assignment, CASE and the usage of the return value of GetParentWorker?
I think this is similar to Ian's, but I'll post for a slightly different approach to the indent level. I think you definitely want to put that indent level into the table with some indexing or this is going to be slow on large tables.
I'm using a CTE to calculate the indent level (basically just adding and subtracting one whenever we hit start or end, using a window function on preceding rows with a special case on ending worker in the current row). Outside of this toy solution, you'd want to limit the preceding rows to rows without an assigned worker and also rows up to the last time the level was zero before that.
Then we can just find the prior 'Start Worker' with the same level. These could probably be marked in pre-processing and indexed for quicker lookups.
UPDATE:
Simplified update statement by introducing window function CTE to calculate the worker id. This should reduce individual row lookups and improve performance in the update. See SQL Fiddle
WITH
WorkerNestingLevel AS (
SELECT
AuditLog.LogId
, AuditLog.LogMessage
, SUM( CASE LogMessage WHEN 'Start Worker' THEN 1 WHEN 'End Worker' THEN -1 ELSE 0 END ) OVER (ORDER BY LogId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
+ CASE LogMessage WHEN 'End Worker' THEN 1 ELSE 0 END AS [WorkerLevel]
FROM
AuditLog
)
, WorkerBatch AS (
SELECT
WorkerNestingLevel.LogId
, MAX( CASE WorkerNestingLevel.LogMessage WHEN 'Start Worker' THEN WorkerNestingLevel.LogId ELSE NULL END) OVER (PARTITION BY WorkerNestingLevel.WorkerLevel ORDER BY WorkerNestingLevel.LogId ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS WorkerId
FROM
WorkerNestingLevel
)
UPDATE
AuditLog
SET
WorkerId = WorkerBatch.WorkerId
FROM
AuditLog
JOIN
WorkerBatch ON (WorkerBatch.LogID = AuditLog.LogId);
My apologies for misunderstanding at the first attempt, hopefully I've understood this time that each 'End Worker' value cancels out one of the 'Start Worker's that precedes it. Here it is using a WITH statement that generates a dataset with a field called indent which you need to establish how far back to look for the correct [Log Entry ID]. Does that meet the requirement?
WITH indenttable AS (SELECT [Log Entry ID]
, [Log Message]
, ((SELECT COUNT(*)
FROM yourtable y2
WHERE [Log Message]='Start Worker'
AND y2.[Log Entry ID]<=yourtable.[Log Entry ID])
-(SELECT COUNT(*)
FROM yourtable y2
WHERE [Log Message]='End Worker'
AND y2.[Log Entry ID]<yourtable.[Log Entry ID])) indent
FROM yourtable)
UPDATE yourtable
SET worker=(
SELECT TOP(1) [Log Entry ID]
FROM indenttable y2
WHERE [Log Message]='Start Worker'
AND y2.[Log Entry ID]<=indenttable.[Log Entry ID]
AND y2.indent<=indenttable.indent
ORDER BY [Log Entry ID] DESC)
FROM indenttable JOIN yourtable ON indenttable.[Log Entry ID]=yourtable.[Log Entry ID];

Long running job

I am not sure what is going on? I still get an email even though the job stopped running at 11:50 pm which clearly is less than thean 7 hours being that it started at 7 pm last night..It is suppose to email me if the job runs longer than 7 hours and for some reason yesterday it worked in test but today its not..Any ideas???
SELECT *
FROM msdb..sysjobactivity aj
JOIN msdb..sysjobs sj on sj.job_id = aj.job_id
WHERE DATEDIFF(HOUR,aj.start_execution_date,GetDate())> 7
AND aj.start_execution_date IS NOT NULL
AND sj.name = 'Nightly_Job'
and not exists ( -- make sure this is the most recent run
select 1
from msdb..sysjobactivity new
where new.job_id = aj.job_id
and new.start_execution_date > aj.start_execution_date)
if ##ROWCOUNT > 0
BEGIN
USE msdb
EXEC sp_send_dbmail
#profile_name = 'DB_Mail',
#recipients = 'xxx#yyy.com',
#subject = 'T-SQL Query Result',
#body = 'The Nightly_Job has been running 7
The problem with your query is that it only checks how long has passed since the job was started... it doesn't take into account when the job completed.
If there are no other executions of the job within 7 hours, then your check that limits the query to the most recent run doesn't exclude the previously completed job... your query then returns the job that was started over 7 hours ago, but in this case completed within 4 hours.
To fix your query to exclude completed jobs, modify your query as follows:
SELECT *
FROM
msdb..sysjobactivity aj
JOIN msdb..sysjobs sj on sj.job_id = aj.job_id
WHERE
DATEDIFF(HOUR, aj.start_execution_date,
ISNULL(aj.stop_execution_date, GetDate()) )> 7
AND sj.name = 'Nightly_Job'
AND NOT EXISTS ( -- make sure this is the most recent run
SELECT 1
FROM msdb..sysjobactivity new
WHERE new.job_id = aj.job_id
AND new.start_execution_date > aj.start_execution_date)

Need some help in creating a query in SQL?

I have 2 following tables :
Ticket(ID, Problem, Status,Priority, LoggedTime,CustomerID*, ProductID*);
TicketUpdate(ID,Message, UpdateTime,TickedID*,StaffID*);
Here is a question to be answered:
Close all support tickets which have not been updated for at least 24 hours. This will be records that have received at least one update from a staff member and no further updates from the customer (or staff member) for at least 24 hours.
My query is:
UPDATE Ticket SET Status = 'closed' FROM TicketUpdate
WHERE(LoggedTime - MAX(UpdateTime))> 24
AND Ticket.ID = TicketUpdate.TicketID;
When I run this query on mysql it says that "<" does not exist.
Can you tell me is my query right to for calculating the records which have not been updated for at least 24 hours and if it is right what should I do use instead of "<"?
... records that have received at least one update from a staff member and
no further updates from the customer (or staff member) for at least 24
hours.
So, effectively, the last update must have been done by a staff member and be older than 24 hours. That covers it all.
(BTW, you have a typo: TickedID -> I use ticketid here.)
UPDATE ticket t
SET status = 'closed'
FROM (
SELECT DISTINCT ON (1)
ticketid
,first_value(updatetime) OVER w AS last_up
,first_value(staffid) OVER w AS staffid
FROM ticketupdate
-- you could join back to ticket here and eliminate 'closed' ids right away
WINDOW w AS (PARTITION BY ticketid ORDER BY updateTime DESC)
) tu
WHERE tu.ticketid = t.id
AND tu.last_up < (now()::timestamp - interval '24 hours')
AND tu.staffid > 1 -- whatever signifies "update from a staff member"
AND t.status IS DISTINCT FROM 'closed'; -- to avoid pointless updates
Note that PostgreSQL folds identifiers to lower case if not double-quoted. I advise to stay away from mixed case identifiers to begin with.
If you are working with postgreSQL then this should work
UPDATE Ticket SET Status = 'closed' FROM TicketUpdate
WHERE abs(extract(epoch from LoggedTime - MAX(UpdateTime))) >24
AND Ticket.ID = TicketUpdate.TicketID;

sql server replication - get last synchronization date from query

Does anyone know the query the last synchronization date from sql server (2008).
It is the same information displayed in replication monitor, but I want to be able to get that date from a query.
I created a view like this to get last date by the subscriber
select subscriber_name, max(start_time) as last_sync
from msMerge_sessions inner join msMerge_agents
on msmerge_agents.id = msmerge_sessions.agent_id
group by subscriber_name
I called the view 'LastSync' - I then joined that view like this to get a representation similar to what the replication monitor shows.
SELECT dbo.LastSync.id, dbo.LastSync.subscriber_name, dbo.LastSync.creation_date, dbo.LastSync.last_sync,
distribution.dbo.MSmerge_sessions.estimated_upload_changes + distribution.dbo.MSmerge_sessions.estimated_download_changes AS estimate_rows,
distribution.dbo.MSmerge_sessions.upload_inserts + distribution.dbo.MSmerge_sessions.upload_updates + distribution.dbo.MSmerge_sessions.upload_deletes + distribution.dbo.MSmerge_sessions.download_inserts
+ distribution.dbo.MSmerge_sessions.download_updates + distribution.dbo.MSmerge_sessions.download_deletes AS actual_rows,
distribution.dbo.MSmerge_sessions.duration AS total_seconds, distribution.dbo.MSmerge_sessions.percent_complete,
distribution.dbo.MSmerge_sessions.delivery_rate, CASE (runstatus)
WHEN 1 THEN 'Start' WHEN 2 THEN 'Succeed' WHEN 3 THEN 'In Progress' WHEN 4 THEN 'Idle' WHEN 5 THEN 'Retry' WHEN 6 THEN 'Fail' END AS Status
FROM distribution.dbo.MSmerge_sessions INNER JOIN
dbo.LastSync ON dbo.LastSync.id = distribution.dbo.MSmerge_sessions.agent_id AND distribution.dbo.MSmerge_sessions.start_time = dbo.LastSync.last_sync
You can see a lot of info about merge sessions by using the system table msMerge_sessions:
select * from msMerge_sessions
Depending on the info you need, use the other system tables available in your database.
For Answered Number 3
Great Effort but there're some modification On view for ability running Query
---- Create View LastSync as below
Create View LastSync As
select subscriber_name, max(start_time) as last_sync, ID, creation_date
from msMerge_sessions inner join msMerge_agents
on msmerge_agents.id = msmerge_sessions.agent_id
group by subscriber_name, ID, creation_date
Go
---- Run Below Query
SELECT dbo.LastSync.id, dbo.LastSync.subscriber_name,
dbo.LastSync.creation_date, dbo.LastSync.last_sync,
distribution.dbo.MSmerge_sessions.estimated_upload_changes +
distribution.dbo.MSmerge_sessions.estimated_download_changes AS
estimate_rows, distribution.dbo.MSmerge_sessions.upload_inserts +
distribution.dbo.MSmerge_sessions.upload_updates +
distribution.dbo.MSmerge_sessions.upload_deletes +
distribution.dbo.MSmerge_sessions.download_inserts
+ distribution.dbo.MSmerge_sessions.download_updates + distribution.dbo.MSmerge_sessions.download_deletes AS actual_rows,
distribution.dbo.MSmerge_sessions.duration AS total_seconds,
distribution.dbo.MSmerge_sessions.percent_complete,
distribution.dbo.MSmerge_sessions.delivery_rate, CASE (runstatus)
WHEN 1 THEN 'Start' WHEN 2 THEN 'Succeed' WHEN 3 THEN 'In Progress'
WHEN 4 THEN 'Idle' WHEN 5 THEN 'Retry' WHEN 6 THEN 'Fail' END AS
Status FROM distribution.dbo.MSmerge_sessions INNER JOIN dbo.LastSync
ON dbo.LastSync.id = distribution.dbo.MSmerge_sessions.agent_id AND
distribution.dbo.MSmerge_sessions.start_time = dbo.LastSync.last_sync
-- Good Luck