SQL query to list head blockers - sql-server

Is there a way to query a database either by sql query or C# to get me a list or datatable of head blockers currently locking up the database?

Use the following SQL, replacing 'MyDatabaseName' with either; the name of your database, or the value, NULL.
DECLARE
#Database NVARCHAR(MAX) = 'MyDatabaseName'
SELECT
s.login_name AS [Login]
, ISNULL(db_name(p.dbid), N'') AS [Database]
, ISNULL(t.task_state, N'') AS [Task State]
, ISNULL(r.command, N'') AS [Command]
, s.cpu_time AS [Total CPU (ms)]
, (s.reads + s.writes) * 8 / 1024 AS [Total Physical I/O (MB)]
, s.memory_usage * 8192 / 1024 AS [Memory Use (KB)]
FROM
sys.dm_exec_sessions AS s
LEFT OUTER JOIN sys.dm_exec_requests AS r ON (s.session_id = r.session_id)
LEFT OUTER JOIN sys.dm_os_tasks AS t ON (r.session_id = t.session_id AND r.request_id = t.request_id)
LEFT OUTER JOIN sys.dm_exec_requests AS r2 ON (s.session_id = r2.blocking_session_id)
LEFT OUTER JOIN sys.sysprocesses AS p ON (s.session_id = p.spid)
WHERE
r2.session_id IS NOT NULL
AND (r.blocking_session_id = 0 OR r.session_id IS NULL)
AND (#Database IS NULL OR ISNULL(db_name(p.dbid), N'') = #Database)
ORDER BY
s.cpu_time DESC
Note: A value of NULL will check all databases within that server.

Related

SQL Server 2017 vs SQL Server 2012 performance problem

I have SQL code that is run on SQL Server 2017 in less than 200 ms, but the same code on SQL Server 2012 takes more than 3 seconds - can anyone tell me:
why is this happening
how do I solve it
select count(*) from dbo.mConsultationQuestionsReplies = 1,300,000
This is my code:
DECLARE #maxCount int;
DECLARE #ddlIds nvarchar(max);
SET #maxCount = 6;
SET #ddlIds = '4,8,840,779,10,813,3,18,7,918';
IF OBJECT_ID('tempdb..#rList') IS NOT NULL
DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL
DROP TABLE #docList
SELECT
rd.UserID,
(CASE
WHEN ids1.value IS NULL
THEN CAST(ids2.value AS int)
ELSE CAST(ids1.value AS int)
END) [cid]
INTO
#docList
FROM
mDJDoctors [rd]
LEFT JOIN
dbo.[mDJDoctorsSpeciality] [rs] ON rd.DoctorID = rs.doctorId
LEFT JOIN
dbo.mDJSpecialtyCategory [rca] ON rca.SpecialtyId = rs.specialId
LEFT JOIN
STRING_SPLIT(#ddlIds, ',') [ids1] ON rca.CategoryId = ids1.value
LEFT JOIN
dbo.mDJDoctorsSpecialtyAbove [ars] ON ars.doctorId = rd.DoctorID
LEFT JOIN
dbo.mDJSpecialtyAboveCategory [arca] ON arca.AboveSpecialtyId = ars.SpecialtyAboveId
LEFT JOIN
STRING_SPLIT(#ddlIds, ',') [ids2] ON [arca].CategoryId = ids2.value
WHERE
[ids1].value IS NOT NULL
OR [ids2].value IS NOT NULL
SELECT *
INTO #rList
FROM
(SELECT
*,
ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber
FROM
(SELECT DISTINCT r.ReplyUserID, r.ReplyDateInsert, d.cid
FROM dbo.mConsultationQuestionsReplies[r]
JOIN #docList [d] ON r.ReplyUserID = d.UserID
WHERE r.ReplyId IN (SELECT MAX(r.ReplyId)[id]
FROM dbo.mConsultationQuestionsReplies[r]
JOIN #docList [d] on r.ReplyUserID = d.UserID
GROUP BY d.cid, d.UserID)) [t]) [t]
WHERE
t.rowNumber <= #maxCount
SELECT
u.FirstName AS DoctorName,
u.UserID AS DoctorUserId,
sp.specialFaName AS DoctorSpecialty,
ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
md.DoctorGUID,
md.DoctorID,
cp.ProfileISOnline,
p.ProfilePicture AS DoctorProfilePicture,
p.ProfileDateInserted,
r.ReplyDateInsert AS LastReplyDateInsert,
r.cid
FROM
dbo.mDJDoctors AS md
INNER JOIN
dbo.Core_Users AS u ON md.UserID = u.UserID
INNER JOIN
dbo.Core_Profiles AS p ON u.UserID = p.UserID
INNER JOIN
(SELECT * FROM #rList) [r] ON r.ReplyUserID = u.UserID
INNER JOIN
dbo.mConsultationDocterProfile AS cp ON cp.UserID = u.UserID
LEFT OUTER JOIN
dbo.mDJDoctorsSpeciality AS mdad ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN
dbo.mDJSpecialty AS sp ON mdad.specialId = sp.specialId
LEFT OUTER JOIN
dbo.mDJDoctorsSpecialtyAbove AS mdad2 ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN
dbo.mDJSpecialtyAbove AS ab ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE
cp.ProfileISOnline = 1
update :
base on guid from marc-s , i removed STRING_SPLIT and new result is
declare #maxCount int;
set #maxCount = 6;
IF OBJECT_ID('tempdb..#rList') IS NOT NULL DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL DROP TABLE #docList
select rd.UserID, (case when arca.CategoryId is null then cast(rca.CategoryId as int) else cast(arca.CategoryId as int) end)[cid] into #docList
from mDJDoctors [rd] WITH (NOLOCK)
left join dbo.[mDJDoctorsSpeciality] [rs] WITH (NOLOCK) on rd.DoctorID = rs.doctorId
left join dbo.mDJSpecialtyCategory [rca] WITH (NOLOCK) on rca.SpecialtyId = rs.specialId
left join dbo.mDJDoctorsSpecialtyAbove [ars] WITH (NOLOCK) on ars.doctorId = rd.DoctorID
left join dbo.mDJSpecialtyAboveCategory [arca] WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId
where arca.CategoryId in (4,8,840,779,10,813,3,18,7,918) or rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
select * into #rList from (
select * , ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber from (
select distinct r.ReplyUserID, r.ReplyDateInsert, d.cid
from dbo.mConsultationQuestionsReplies[r] WITH (NOLOCK)
join #docList [d] on r.ReplyUserID = d.UserID
where r.ReplyId in(
select max(r.ReplyId)[id]
from dbo.mConsultationQuestionsReplies[r] WITH (NOLOCK)
join #docList [d] on r.ReplyUserID = d.UserID
group by d.cid,d.UserID
))[t])[t] where t.rowNumber <= #maxCount
SELECT distinct
u.FirstName AS DoctorName,
u.UserID AS DoctorUserId,
sp.specialFaName AS DoctorSpecialty,
ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
md.DoctorGUID,
md.DoctorID,
cp.ProfileISOnline,
p.ProfilePicture AS DoctorProfilePicture,
p.ProfileDateInserted,
r.ReplyDateInsert AS LastReplyDateInsert,
r.cid
FROM dbo.mDJDoctors AS md WITH (NOLOCK)
INNER JOIN dbo.Core_Users AS u WITH (NOLOCK)
ON md.UserID = u.UserID
INNER JOIN dbo.Core_Profiles AS p WITH (NOLOCK)
ON u.UserID = p.UserID
INNER JOIN
(
select * from #rList
) [r]
ON r.ReplyUserID = u.UserID
INNER JOIN dbo.mConsultationDocterProfile AS cp WITH (NOLOCK)
ON cp.UserID = u.UserID
LEFT OUTER JOIN dbo.mDJDoctorsSpeciality AS mdad WITH (NOLOCK)
ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN dbo.mDJSpecialty AS sp WITH (NOLOCK)
ON mdad.specialId = sp.specialId
LEFT OUTER JOIN dbo.mDJDoctorsSpecialtyAbove AS mdad2 WITH (NOLOCK)
ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN dbo.mDJSpecialtyAbove AS ab WITH (NOLOCK)
ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE cp.ProfileISOnline = 1
order by cid, LastReplyDateInsert
its take 200 ms in sql 2017 and take 1038ms in sql 2012
update 3:
this i my execution plans xml for 2012 and 2017
2012 and 2017 execution plans
update 4:
server config
The SQL Server 2012 database is missing an index (compared to SQL Server 2017) on [dbo].[Core_Profiles]
For SQL Server 2012, there is no index on [dbo].[Core_Profiles].Userid and although the query has only 52 distinct userids, it scans the full [Core_Profiles] table (~0.5mil rows) to hash match it with 52 rows and return: 52 rows (the scale diff is considerable).
For SQL Server 2017, there is the [missing_index_9245_9243] (which also includes the ProfilePicture{?}). Instead of half million table scan, it performs a 52 rows/times loops join. There is still a keylookup to [Core_Profiles] for the retrieval of ProfileDateInserted.
The first thing to try, would be to create an index on [dbo].[Core_Profiles].Userid. Whether you choose to include the ProfilePicture is a bit irrelevant to the particular query since a key lookup is performed anyway.
A side suggestion would be to create indexes on the #temp tables. Also the retrieval of the mDJDoctorsSpeciality & mDJDoctorsSpecialtyAbove (the set of 4 table outer-joins) is used twice in the batch. Wouldn't the first execution satisfy the second(returned resultset?), so why not store it and use the #temp table instead of querying the tables again (caveat: have not looked at the query logic/model at all, only at the plans) . Most likely, the queries could be nested (inner joins), something like:
from mDJDoctors [rd] WITH (NOLOCK)
left join
(
dbo.[mDJDoctorsSpeciality] [rs] WITH (NOLOCK)
join dbo.mDJSpecialtyCategory [rca] WITH (NOLOCK) on rca.SpecialtyId = rs.specialId and rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on rd.DoctorID = rs.doctorId
left join
(
dbo.mDJDoctorsSpecialtyAbove [ars] WITH (NOLOCK)
join dbo.mDJSpecialtyAboveCategory [arca] WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId and arca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on ars.doctorId = rd.DoctorID
where rs.doctorId is not null or rd.DoctorID is not null
on a second thought, isn't this a union?
(
DoctorId from dbo.mDJSpecialtyCategory....
union
DoctorId from dbo.mDJSpecialtyAboveCategory....
) as X
join mDJDoctors [rd] on DoctorId....
If I would be in your situation I would first look at the differences between the 2 instances; there are a lot of things that can impact performance of a query, just looking at the code is not enough in your case (running the same query on 2 separate instances).
So, take a look at the memory allocated to each instance, the settings (MAXDOP and CTP are a good start), are they running on the same machine? If not, are there any significant HW differences? Is there more usage (other people or applications running queries) of your SQL Server 2017 than your SQL Server 2012? Do you have the same amount of data on both servers? Are your indexes the same and are they maintained on both instances (could it be that you have a high level of fragmentation on your SQL Server 2017)? Also, take a look at the execution plans to see if they are identical on both servers.
I know it seems like a lot of questions, but without knowing the full context is hard to answer; any of the above could be the culprit for the slowness.

Getting SQL Server Activity Monitor's Output using t-SQL

How to get the SQL Server Activity Monitor's output using T-SQL???
In order to get exactly same output as Activity Monitor; I have created a following script.
If you use this script, you don't need sp_who2 or activity monitor to run.
The script that I have created will display the following things:
[Session ID]
[User Process]
[Login]
[Blocked By]
[Head Blocker]
[DatabaseName]
[Task State]
[Command]
[statement_text] --It will display the statement which is being executed presently.
[command_text] ----- It will display the Stored Procedure's Name.
[Total CPU (ms)]
'Elapsed Time (in Sec)'
[Wait Time (ms)]
[Wait Type]
[Wait Resource]
[Memory Use (KB)]
[Host Name]
[Net Address]
[Workload Group]
[Application]
My Activity Monitor's Script is as follows:
/* ACTIVITY MONITOR'S OUTPUT along with statement_text and command_text */ /* Processes */
SELECT [Session ID] = s.session_id,
[User Process] = CONVERT(CHAR(1), s.is_user_process),
[Login] = s.login_name,
[Blocked By] = ISNULL(CONVERT (varchar, w.blocking_session_id), ''),
[Head Blocker] =
CASE
-- session has an active request, is blocked, but is blocking others or session is idle but has an open tran and is blocking others
WHEN r2.session_id IS NOT NULL AND (r.blocking_session_id = 0 OR r.session_id IS NULL) THEN '1'
-- session is either not blocking someone, or is blocking someone but is blocked by another party
ELSE ''
END,
[DatabaseName] = ISNULL(db_name(r.database_id), N''),
[Task State] = ISNULL(t.task_state, N''),
[Command] = ISNULL(r.command, N''),
[statement_text] = Substring(st.TEXT, (r.statement_start_offset / 2) + 1,
( ( CASE r.statement_end_offset WHEN - 1 THEN Datalength(st.TEXT)
ELSE r.statement_end_offset
END - r.statement_start_offset ) / 2 ) + 1), ----It will display the statement which is being executed presently.
[command_text] =Coalesce(Quotename(Db_name(st.dbid)) + N'.' + Quotename(Object_schema_name(st.objectid, st.dbid)) + N'.' + Quotename(Object_name(st.objectid, st.dbid)), ''), -- It will display the Stored Procedure's Name.
[Total CPU (ms)] = r.cpu_time,
r.total_elapsed_time / (1000.0) 'Elapsed Time (in Sec)',
[Wait Time (ms)] = ISNULL(w.wait_duration_ms, 0),
[Wait Type] = ISNULL(w.wait_type, N''),
[Wait Resource] = ISNULL(w.resource_description, N''),
[Total Physical I/O (MB)] = (s.reads + s.writes) * 8 / 1024,
[Memory Use (KB)] = s.memory_usage * 8192 / 1024,
--[Open Transactions Count] = ISNULL(r.open_transaction_count,0),
--[Login Time] = s.login_time,
--[Last Request Start Time] = s.last_request_start_time,
[Host Name] = ISNULL(s.host_name, N''),
[Net Address] = ISNULL(c.client_net_address, N''),
-- [Execution Context ID] = ISNULL(t.exec_context_id, 0),
-- [Request ID] = ISNULL(r.request_id, 0),
[Workload Group] = N'',
[Application] = ISNULL(s.program_name, N'')
FROM sys.dm_exec_sessions s
LEFT OUTER JOIN sys.dm_exec_connections c ON (s.session_id = c.session_id)
LEFT OUTER JOIN sys.dm_exec_requests r ON (s.session_id = r.session_id)
LEFT OUTER JOIN sys.dm_os_tasks t ON (r.session_id = t.session_id
AND r.request_id = t.request_id)
LEFT OUTER JOIN
( -- In some cases (e.g. parallel queries, also waiting for a worker), one thread can be flagged as
-- waiting for several different threads. This will cause that thread to show up in multiple rows
-- in our grid, which we don't want. Use ROW_NUMBER to select the longest wait for each thread,
-- and use it as representative of the other wait relationships this thread is involved in.
SELECT *,
ROW_NUMBER() OVER (PARTITION BY waiting_task_address
ORDER BY wait_duration_ms DESC) AS row_num
FROM sys.dm_os_waiting_tasks ) w ON (t.session_id = w.session_id)
AND w.row_num = 1
LEFT OUTER JOIN sys.dm_exec_requests r2 ON (r.session_id = r2.blocking_session_id) OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
WHERE s.session_Id > 50 -- Ignore system spids.
ORDER BY s.session_id --,[Total CPU (ms)] desc ;
Not exactly sure what you are looking for, but this should give you something similar what you see on the activity monitor (not completely but similar).
SELECT
P.spid,
RIGHT(CONVERT(VARCHAR, DATEADD(MS, DATEDIFF(MS, P.last_batch, GETDATE()), '1900-01-01'), 121), 12) AS [BATCH_DURATION],
P.program_name,
P.hostname AS HOST_NAME,
P.loginame AS LOGIN_NAME
FROM master.dbo.sysprocesses AS P
WHERE
P.spid > 50 AND
P.status NOT IN ('background', 'sleeping') AND
P.cmd NOT IN
(
'AWAITING COMMAND',
'MIRROR HANDLER',
'LAZY WRITER',
'CHECKPOINT SLEEP',
'RA MANAGER'
)
ORDER BY 2
The reason we are looking for SPID > 50 is because processes that has ID smaller than 50 belongs to internal operations. Anything greater than 50 should be for user actions.
Also, you can see all the blockings etc. on a db, you could try something like this.
SELECT
db.name AS DB_NAME,
tl.request_session_id AS REQUESTING_SESSION,
wt.blocking_session_id AS BLOCKING_SESSION,
OBJECT_NAME(p.OBJECT_ID) AS BLOCKED_OBJECT,
tl.resource_type AS RESOURCE_TYPE,
h1.TEXT AS REQUEST_QUERY,
h2.TEXT AS BLOCKING_QUERY,
tl.request_mode
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
You can possibly combine these to get what exactly you are looking for.
Hope this helps.

Convert query with system objects from SQL 2000 to 2005/2008

I have some SQL I need to get working on SQL 2005/2008. The SQL is from SQL 2000 and uses some system objects to make it work.
master.dbo.spt_provider_types
master.dbo.syscharsets
systypes
syscolumns
sysobjects
I know SQL 2005 does no longer use system tables and I can get the same information from views, but I am looking for a solution that will work for both SQL 2000 and 2005/2008. Any ideas?
select top 100 percent
TABLE_CATALOG = db_name(),
TABLE_SCHEMA = user_name(o.uid),
TABLE_NAME = o.name,
COLUMN_NAME = c.name,
ORDINAL_POSITION = convert(int,
(
select count(*)
from syscolumns sc
where sc.id = c.id
AND sc.number = c.number
AND sc.colid <= c.colid
)),
IS_COMPUTED = convert(bit, c.iscomputed)
from
syscolumns c left join syscomments m on c.cdefault = m.id and m.colid = 1,
sysobjects o,
master.dbo.spt_provider_types d,
systypes t,
master.dbo.syscharsets a_cha /* charset/1001, not sortorder.*/
where
o.name = #table_name and
permissions(o.id, c.name) <> 0
and (o.type in ('U','V','S') OR (o.type in ('TF', 'IF') and c.number = 0))
and o.id = c.id
and t.xtype = d.ss_dtype
and c.length = case when d.fixlen > 0 then d.fixlen else c.length end
and c.xusertype = t.xusertype
and a_cha.type = 1001 /* type is charset */
and a_cha.id = isnull(convert(tinyint, CollationPropertyFromID(c.collationid, 'sqlcharset')),
convert(tinyint, ServerProperty('sqlcharset'))) -- make sure there's one and only one row selected for each column
order by 2, 3, c.colorder
) tbl where IS_COMPUTED = 0
you need to read this Microsoft doc: Mapping SQL Server 2000 System Tables to SQL Server 2005 System Views
EDIT based on OP's comments
for YourTable, my query here will list the:
schema.tablename
ColumnName
TableType
DataType
Nullable status
Identity, computed column, and check constraint info
this runs on SQL Server 2005, not sure about 2000.
SELECT
sh.name+'.'+o.name AS TableName
,s.name as ColumnName
,o.type_desc AS TableType
,CASE
WHEN t.name IN ('char','varchar') THEN t.name+'('+CASE WHEN s.max_length<0 then 'MAX' ELSE CONVERT(varchar(10),s.max_length) END+')'
WHEN t.name IN ('nvarchar','nchar') THEN t.name+'('+CASE WHEN s.max_length<0 then 'MAX' ELSE CONVERT(varchar(10),s.max_length/2) END+')'
WHEN t.name IN ('numeric') THEN t.name+'('+CONVERT(varchar(10),s.precision)+','+CONVERT(varchar(10),s.scale)+')'
ELSE t.name
END AS DataType
,CASE
WHEN s.is_nullable=1 THEN 'NULL'
ELSE 'NOT NULL'
END AS Nullable
,CASE
WHEN ic.column_id IS NULL THEN ''
ELSE ' identity('+ISNULL(CONVERT(varchar(10),ic.seed_value),'')+','+ISNULL(CONVERT(varchar(10),ic.increment_value),'')+')='+ISNULL(CONVERT(varchar(10),ic.last_value),'null')
END
+CASE
WHEN sc.column_id IS NULL THEN ''
ELSE ' computed('+ISNULL(sc.definition,'')+')'
END
+CASE
WHEN cc.object_id IS NULL THEN ''
ELSE ' check('+ISNULL(cc.definition,'')+')'
END
AS MiscInfo
FROM sys.objects o
INNER JOIN sys.columns s ON o.object_id=s.object_id
INNER JOIN sys.types t ON s.system_type_id=t.system_type_id and t.is_user_defined=0
INNER JOIN sys.schemas sh on o.schema_id=sh.schema_id
LEFT OUTER JOIN sys.identity_columns ic ON s.object_id=ic.object_id AND s.column_id=ic.column_id
LEFT OUTER JOIN sys.computed_columns sc ON s.object_id=sc.object_id AND s.column_id=sc.column_id
LEFT OUTER JOIN sys.check_constraints cc ON s.object_id=cc.parent_object_id AND s.column_id=cc.parent_column_id
WHERE sh.name='dbo' --schema name
AND o.name='YourTable' --table name
--AND s.name='YourColumn'
ORDER BY s.column_id
If you trying to make the query work in SQL 2000 and SQL 2005, then it should mostly work as is. Microsoft created compatibility views for the system tables specifically so that legacy code would not break. The one problem might be the spt_provider_types table. For that you will either need to use something else like the INFORMATION_SCHEMA views or you can recreate the spt_ tables by running a script in the installs folder on the SQL 2005 system called u_tables.sql.

How can i link a sql server job name

to the SSRS report server process that uses it? the name looks like a guid, but i need to find the reporting services reports that use it.
thanks very much
Here's a query I blogged about a while back that does the join:
;WITH cte (job_id, job_name, execution_time, execution_order)
AS
(
SELECT DISTINCT j.job_id
,j.name
,CONVERT(datetime, STUFF(STUFF(run_date,7,0,'/'),5,0,'/')
+ SPACE(1)
+ STUFF(STUFF(RIGHT('000000' + CONVERT(varchar(20), run_time), 6),5,0,':'),3,0,':'))
,ROW_NUMBER() OVER (PARTITION BY j.job_id ORDER BY CONVERT(datetime, STUFF(STUFF(run_date,7,0,'/'),5,0,'/')
+ SPACE(1)
+ STUFF(STUFF(RIGHT('000000' + CONVERT(varchar(20), run_time), 6),5,0,':'),3,0,':')) DESC)
FROM msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.syscategories c ON j.category_id = c.category_id
LEFT OUTER JOIN msdb.dbo.sysjobhistory jh ON j.job_id = jh.job_id
WHERE c.name ='Report Server'
)
SELECT
x.job_name
,c.name
,x.execution_time
,c.path
,su.description
,CONVERT(varchar(max), su.ExtensionSettings) as ExtensionSettings
,'EXEC msdb..sp_start_job ''' + x.job_name + '''' as SQLStatement
FROM cte x
INNER JOIN dbo.Schedule sc ON x.job_name = CONVERT(varchar(100), sc.ScheduleID)
INNER JOIN dbo.ReportSchedule rs ON sc.ScheduleID = rs.ScheduleID
INNER JOIN dbo.Subscriptions su ON rs.SubscriptionID = su.SubscriptionID
INNER JOIN dbo.Catalog c ON su.Report_OID = c.ItemID
WHERE execution_order = 1
ORDER BY 3, 2
There doesn't appear to be a straightforward method to find this out.
The following query lists the subscription IDs and the reports to which they link
select s.SubscriptionID, c.Path
from ReportServer.dbo.Subscriptions as s
JOIN ReportServer.dbo.Catalog as c
on ItemID = Report_OID
The subscription ID is then referenced inside the job step, in the following format.
exec ReportServer.dbo.AddEvent #EventType='TimedSubscription', #EventData='~subscriptionID~'
It should be possible to write a query to join it all together, but I don't have time right now. I will try and update the question later.

How to find largest objects in a SQL Server database?

How would I go about finding the largest objects in a SQL Server database? First, by determining which tables (and related indices) are the largest and then determining which rows in a particular table are largest (we're storing binary data in BLOBs)?
Are there any tools out there for helping with this kind of database analysis? Or are there some simple queries I could run against the system tables?
I've been using this SQL script (which I got from someone, somewhere - can't reconstruct who it came from) for ages and it's helped me quite a bit understanding and determining the size of indices and tables:
SELECT
t.name AS TableName,
i.name as indexName,
sum(p.rows) as RowCounts,
sum(a.total_pages) as TotalPages,
sum(a.used_pages) as UsedPages,
sum(a.data_pages) as DataPages,
(sum(a.total_pages) * 8) / 1024 as TotalSpaceMB,
(sum(a.used_pages) * 8) / 1024 as UsedSpaceMB,
(sum(a.data_pages) * 8) / 1024 as DataSpaceMB
FROM
sys.tables t
INNER JOIN
sys.indexes i ON t.object_id = i.object_id
INNER JOIN
sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON p.partition_id = a.container_id
WHERE
t.name NOT LIKE 'dt%' AND
i.object_id > 255 AND
i.index_id <= 1
GROUP BY
t.name, i.object_id, i.index_id, i.name
ORDER BY
object_name(i.object_id)
Of course, you can use another ordering criteria, e.g.
ORDER BY SUM(p.rows) DESC
to get the tables with the most rows, or
ORDER BY SUM(a.total_pages) DESC
to get the tables with the most pages (8K blocks) used.
In SQL Server 2008, you can also just run the standard report Disk Usage by Top Tables. This can be found by right clicking the DB, selecting Reports->Standard Reports and selecting the report you want.
This query help to find largest table in you are connection.
SELECT TOP 1 OBJECT_NAME(OBJECT_ID) TableName, st.row_count
FROM sys.dm_db_partition_stats st
WHERE index_id < 2
ORDER BY st.row_count DESC
You may also use the following code:
USE AdventureWork
GO
CREATE TABLE #GetLargest
(
table_name sysname ,
row_count INT,
reserved_size VARCHAR(50),
data_size VARCHAR(50),
index_size VARCHAR(50),
unused_size VARCHAR(50)
)
SET NOCOUNT ON
INSERT #GetLargest
EXEC sp_msforeachtable 'sp_spaceused ''?'''
SELECT
a.table_name,
a.row_count,
COUNT(*) AS col_count,
a.data_size
FROM #GetLargest a
INNER JOIN information_schema.columns b
ON a.table_name collate database_default
= b.table_name collate database_default
GROUP BY a.table_name, a.row_count, a.data_size
ORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC
DROP TABLE #GetLargest
#marc_s's answer is very great and I've been using it for few years. However, I noticed that the script misses data in some columnstore indexes and doesn't show complete picture. E.g. when you do SUM(TotalSpace) against the script and compare it with total space database property in Management Studio the numbers don't match in my case (Management Studio shows larger numbers). I modified the script to overcome this issue and extended it a little bit:
select
tables.[name] as table_name,
schemas.[name] as schema_name,
isnull(db_name(dm_db_index_usage_stats.database_id), 'Unknown') as database_name,
sum(allocation_units.total_pages) * 8 as total_space_kb,
cast(round(((sum(allocation_units.total_pages) * 8) / 1024.00), 2) as numeric(36, 2)) as total_space_mb,
sum(allocation_units.used_pages) * 8 as used_space_kb,
cast(round(((sum(allocation_units.used_pages) * 8) / 1024.00), 2) as numeric(36, 2)) as used_space_mb,
(sum(allocation_units.total_pages) - sum(allocation_units.used_pages)) * 8 as unused_space_kb,
cast(round(((sum(allocation_units.total_pages) - sum(allocation_units.used_pages)) * 8) / 1024.00, 2) as numeric(36, 2)) as unused_space_mb,
count(distinct indexes.index_id) as indexes_count,
max(dm_db_partition_stats.row_count) as row_count,
iif(max(isnull(user_seeks, 0)) = 0 and max(isnull(user_scans, 0)) = 0 and max(isnull(user_lookups, 0)) = 0, 1, 0) as no_reads,
iif(max(isnull(user_updates, 0)) = 0, 1, 0) as no_writes,
max(isnull(user_seeks, 0)) as user_seeks,
max(isnull(user_scans, 0)) as user_scans,
max(isnull(user_lookups, 0)) as user_lookups,
max(isnull(user_updates, 0)) as user_updates,
max(last_user_seek) as last_user_seek,
max(last_user_scan) as last_user_scan,
max(last_user_lookup) as last_user_lookup,
max(last_user_update) as last_user_update,
max(tables.create_date) as create_date,
max(tables.modify_date) as modify_date
from
sys.tables
left join sys.schemas on schemas.schema_id = tables.schema_id
left join sys.indexes on tables.object_id = indexes.object_id
left join sys.partitions on indexes.object_id = partitions.object_id and indexes.index_id = partitions.index_id
left join sys.allocation_units on partitions.partition_id = allocation_units.container_id
left join sys.dm_db_index_usage_stats on tables.object_id = dm_db_index_usage_stats.object_id and indexes.index_id = dm_db_index_usage_stats.index_id
left join sys.dm_db_partition_stats on tables.object_id = dm_db_partition_stats.object_id and indexes.index_id = dm_db_partition_stats.index_id
group by schemas.[name], tables.[name], isnull(db_name(dm_db_index_usage_stats.database_id), 'Unknown')
order by 5 desc
Hope it will be helpful for someone.
This script was tested against large TB-wide databases with hundreds of different tables, indexes and schemas.
If you are using Sql Server Management Studio 2008 there are certain data fields you can view in the object explorer details window. Simply browse to and select the tables folder. In the details view you are able to right-click the column titles and add fields to the "report". Your mileage may vary if you are on SSMS 2008 express.
I've found this query also very helpful in SqlServerCentral, here is the link to original post
Sql Server largest tables
select name=object_schema_name(object_id) + '.' + object_name(object_id)
, rows=sum(case when index_id < 2 then row_count else 0 end)
, reserved_kb=8*sum(reserved_page_count)
, data_kb=8*sum( case
when index_id<2 then in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count
else lob_used_page_count + row_overflow_used_page_count
end )
, index_kb=8*(sum(used_page_count)
- sum( case
when index_id<2 then in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count
else lob_used_page_count + row_overflow_used_page_count
end )
)
, unused_kb=8*sum(reserved_page_count-used_page_count)
from sys.dm_db_partition_stats
where object_id > 1024
group by object_id
order by
rows desc
In my database they gave different results between this query and the 1st answer.
Hope somebody finds useful

Resources