How to find SQL Object having the text in SQL Server? - sql-server

There was some performance issue in my application in production, I did some investigation and found out that one process is blocking my SP execution. I saw the log in SolarWinds DPA and found out that the process having id 12345 is blocking my SP. then it is showing the query in SQL text.
Query which is blocking
SELECT ColX, ColY.........
FROM [dbo].[Table1] As T1
INNER JOIN [dbo].[Table2] AS T2
ON T1.[PaymentFK] = T2.[PaymentPK]
WHERE (([Col1] = #p0)
OR ([ExtBCol1atchFileFK] IS NULL))
AND ([Col2] = #p1)
AND ([Col3] = #p2)
AND (NOT ([Col4] = 1))
But not giving object names like SP/View/Trigger/Job. I searched this text in all the SPs/Views/Triggers. But could not find the blocking query.
So is there any way to find out in which object exactly this query is being used?

This might help if the script is stored in the database.
SELECT DISTINCT OBJECT_SCHEMA_NAME(object_id), OBJECT_NAME(object_id)
FROM sys.sql_modules (NOLOCK)
WHERE definition LIKE '%search_phrase%'

Related

How to check blocking queries in SQL Server

I have one warehouse server which got data/sync from legacy system 24/7, I noticed some of my reports/sql jobs performance is uncertain and most of the time I heard from DBA team that my query is blocking to other sync process.
From DBA team I came to know command i.e. EXEC SP_WHO2 by which I can identify spid of query which cause blocking by looking into column BlkBy.
Please suggest me how I can avoid blocking and other ways to check blocking in SQL Server
Apart from Sp_Who2 you can use following query to identify blocking in you SQL.
SELECT
db.name DBName,
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
tl.resource_type,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingTest,
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
GO
Also can check detail of particular SPID by using following command.
DBCC INPUTBUFFER(56) — Will give you the Event Info.
KILL 56 -- Will kill the session of this id.
This is a very comprehensive guide. Some basic guidelines though:
Avoid SELECT ... INTO #temp pattern and instead create a table first and use INSERT INTO #Temp SELECT...
Use WITH (NOLOCK) on queries where you can tolerate dirty reads
Ensure proper indexes exist
Use sargable predicates in your WHERE clauses
Talk to your DBA about potentially enabling READ_COMMITTED_SNAPSHOT isolation level
The simplest method is by using the Activity Monitor query within Microsoft’s SQL Server Management Studio (SSMS). To access this query from SSMS: first open up the main window; then click ‘Activity Monitor’ under ‘Tools’; then use either the ‘Processes/Sessions’ tab or specifically select ‘Blocking Processes” from the drop down menu at top left of the monitor window. This will show all currently running processes and their associated session ID's, as well as any transactions they might be involved with such as those that are being blocked by other threads.
You can also check for blocking using a few T-SQL scripts designed explicitly to check locking behavior on working systems. One such script is called SP_WHO2 this simple system-stored procedure displays lock information about active user connections and associated process IDs against all databases running on an instance of SQL server. --Cheers Mike B

Does MSSQL always copy tables when using Linked Server

After googling and looking into the MS documenation (http://msdn.microsoft.com/en-us/library/ms188279.aspx) on linked servers I still couldn't get a clear answer to the following question. I'm thinking about linking 2 SQL Servers so I can create a subset of data from the source DB and insert it into an output DB (with duplicate checks before inserting) but I don't know how MSSQL processes queries that use linked databases.
As far as I know following query will result in LocalServer downloading the FarAwayTable and then executing the query locally (which is killing for performance in my case):
SELECT
f.*
FROM
FarAwayServer.FarAwayDB.dbo.FarAwayTable f,
LocalServer.LocalDb.dbo.LocalTable l
WHERE
f.ID = l.ID
My question is, will MSSQL do the same for the following query or will it only download the result (executing the whole query on the FarAwayServer):
SELECT
*
FROM
FarAwayServer.FarAwayDB.dbo.FarAwayTable f
WHERE
f.ID = 1
It will still act the same (the FarAwayTable table will be downloaded and the query will be executed locally). If you want to execute the query on FarAwayServer you should use OPENQUERY:
SELECT * FROM OPENQUERY([FarAwayServer], 'SELECT * FROM FarAwayDB.dbo.FarAwayTable f WHERE f.ID = 1')

Making one table equal to another without a delete *

I know this is bit of a strange one but if anyone had any help that would be greatly appreciated.
The scenario is that we have a production database at a remote site and a developer database in our local office. Developers make changes directly to the developer db and as part of the deployment process a C# application runs and produces a series of .sql scripts that we can execute on the remote side (essentially delete *, insert) but we are looking for something a bit more elaborate as the downtime from the delete * is unacceptable. This is all reference data that controls menu items, functionality etc of a major website.
I have a sproc that essentially returns a diff of two tables. My thinking is that I can insert all the expected data in to a tmp table, execute the diff, and drop anything from the destination table that is not in the source and then upsert everything else.
The question is that is there an easy way to do this without using a cursor? To illustrate the sproc returns a recordset structured like this:
TableName Col1 Col2 Col3
Dest
Src
Anything in the recordset with TableName = Dest should be deleted (as it does not exist in src) and anything in Src should be upserted in to dest. I cannot think of a way to do this purely set based but my DB-fu is weak.
Any help would be appreciated. Apologies if the explanation is sketchy; let me know if you need anymore details.
Yeah, that sproc would work. Use a FULL JOIN with that table and add a column to indicate insert, update or delete. Then create separate SQL statements for them based on the column indicator. Set based.
Sorry not a FULL JOIN, you'll need to break them down to separate LEFT and RIGHT JOINS. Did this in NotePad, so apologies if it doesn't work:
INSERT INTO tempDeployData(ID,IUDType)
SELECT ed.id, 'D'
FROM tmpDeployData td
RIGHT JOIN existingData ed ON td.id = ed.id
WHERE td.id IS NULL
UPDATE td
SET td.IUDType = CASE WHEN ed.id IS NULL THEN
'I'
ELSE
'U'
END
FROM tmpDeployData td
LEFT JOIN existingData ed ON td.id = ed.id
INSERT INTO existingData(ID,a,b,c)
SELECT td.ID,td.a,td.b,td.c
FROM tmpDeployData td
WHERE td.IUDType = 'I'
DELETE ed
FROM existingData ed
INNER JOIN tmpDeployData td ON ed.ID = td.ID
WHERE td.IUDType = 'D'
UPDATE ed
SET ed.a = td.a,
ed.b = td.b,
ed.c = td.c
FROM existingData ed
INNER JOIN tmpDeployData td ON ed.ID = td.ID
WHERE td.IUDType = 'U'
Just realized you're pulling info into the temptable as a staging table, not the source of the data. In that case you can use the FULL JOIN:
INSERT INTO tmpDeployData(ID,a,b,c,IUDType)
SELECT sd.ID,
sd.a,
sd.b,
sd.c
'IUDType' = CASE WHEN ed.id IS NULL THEN
'I'
WHEN sd.id IS NULL THEN
'D'
ELSE
'U'
END
FROM sourceData sd
FULL JOIN existingData ed ON sd.id = ed.id
Then same DML statements as before.
took at tablediff
tables do not need to participate in replication to run the utility. there's a wonderful -f switch to generate t-sql to put the tables 'in-sync':
Generates a Transact-SQL script to
bring the table at the destination
server into convergence with the table
at the source server. You can
optionally specify a name and path for
the generated Transact-SQL script
file. If file_name is not specified,
the Transact-SQL script file is
generated in the directory where the
utility runs.
There's a much, much easier way to do this assuming you're using SQL Server 2008: The MERGE statement.
Migrating all changes from one table to another is as simple as:
MERGE DestinationTable d
USING SourceTable s
ON d.Id = s.Id
WHEN MATCHED THEN UPDATE
SET d.Col1 = s.Col1, d.Col2 = s.Col2, ...
WHEN NOT MATCHED BY TARGET THEN
INSERT (Id, Col1, Col2, ...)
VALUES (s.Id, s.Col1, s.Col2, ...)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
That's it. DestinationTable will be identical to SourceTable after that.
Why don't you just take a backup of the production database and restore it over your development database? You should have change scripts for all ddl differences from the production database that you can run on the database after the restore and it would test the deployment to production.
edit:
Sorry, just re-read your question, it looks like you are storing your configuration info in your development db and generating your change scripts from that so this wouldn't work.
I would recommend creating change scripts by hand and storing them in source control. Then use sqlcmd or osql and a batch file to run your change scripts on the database.

Last Run Date on a Stored Procedure in SQL Server

We starting to get a lot of stored procedures in our application. Many of them are for custom reports many of which are no longer used. Does anyone know of a query we could run on the system views in SQL Server 2005 that would tell us the last date a stored procedure was executed?
The below code should do the trick (>= 2008)
SELECT o.name,
ps.last_execution_time
FROM sys.dm_exec_procedure_stats ps
INNER JOIN
sys.objects o
ON ps.object_id = o.object_id
WHERE DB_NAME(ps.database_id) = ''
ORDER BY
ps.last_execution_time DESC
Edit 1 : Please take note of Jeff Modens advice below. If you find a procedure here, you can be sure that it is accurate. If you do not then you just don't know - you cannot conclude it is not running.
In a nutshell, no.
However, there are "nice" things you can do.
Run a profiler trace with, say, the stored proc name
Add a line each proc (create a tabel of course)
"INSERT dbo.SPCall (What, When) VALUES (OBJECT_NAME(##PROCID), GETDATE()"
Extend 2 with duration too
There are "fun" things you can do:
Remove it, see who calls
Remove rights, see who calls
Add RAISERROR ('Warning: pwn3d: call admin', 16, 1), see who calls
Add WAITFOR DELAY '00:01:00', see who calls
You get the idea. The tried-and-tested "see who calls" method of IT support.
If the reports are Reporting Services, then you can mine the RS database for the report runs if you can match code to report DataSet.
You couldn't rely on DMVs anyway because they are reset om SQL Server restart.
Query cache/locks are transient and don't persist for any length of time.
Oh, be careful now! All that glitters is NOT gold! All of the “stats” dm views and functions have a problem for this type of thing. They only work against what is in cache and the lifetime of what is in cache can be measured in minutes. If you were to use such a thing to determine which SPs are candidates for being dropped, you could be in for a world of hurt when you delete SPs that were used just minutes ago.
The following excerpts are from Books Online for the given dm views…
sys.dm_exec_procedure_stats
Returns aggregate performance statistics for cached stored procedures. The view contains one row per stored procedure, and the lifetime of the row is as long as the stored procedure remains cached. When a stored procedure is removed from the cache, the corresponding row is eliminated from this view.
sys.dm_exec_query_stats
The view contains one row per query statement within the cached plan, and the lifetime of the rows are tied to the plan itself. When a plan is removed from the cache, the corresponding rows are eliminated from this view.
sys.dm_exec_procedure_stats contains the information about the execution functions, constraints and Procedures etc. But the life time of the row has a limit, The moment the execution plan is removed from the cache the entry will disappear.
Use [yourDatabaseName]
GO
SELECT
SCHEMA_NAME(sysobject.schema_id),
OBJECT_NAME(stats.object_id),
stats.last_execution_time
FROM
sys.dm_exec_procedure_stats stats
INNER JOIN sys.objects sysobject ON sysobject.object_id = stats.object_id
WHERE
sysobject.type = 'P'
ORDER BY
stats.last_execution_time DESC
This will give you the list of the procedures recently executed.
If you want to check if a perticular stored procedure executed recently
SELECT
SCHEMA_NAME(sysobject.schema_id),
OBJECT_NAME(stats.object_id),
stats.last_execution_time
FROM
sys.dm_exec_procedure_stats stats
INNER JOIN sys.objects sysobject ON sysobject.object_id = stats.object_id
WHERE
sysobject.type = 'P'
and (sysobject.object_id = object_id('schemaname.procedurename')
OR sysobject.name = 'procedurename')
ORDER BY
stats.last_execution_time DESC
If you enable Query Store on SQL Server 2016 or newer you can use the following query to get last SP execution. The history depends on the Query Store Configuration.
SELECT
ObjectName = '[' + s.name + '].[' + o.Name + ']'
, LastModificationDate = MAX(o.modify_date)
, LastExecutionTime = MAX(q.last_execution_time)
FROM sys.query_store_query q
INNER JOIN sys.objects o
ON q.object_id = o.object_id
INNER JOIN sys.schemas s
ON o.schema_id = s.schema_id
WHERE o.type IN ('P')
GROUP BY o.name , + s.name
This works fine on 2005 (if the plan is in the cache)
USE YourDb;
SELECT qt.[text] AS [SP Name],
qs.last_execution_time,
qs.execution_count AS [Execution Count]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE qt.dbid = DB_ID()
AND objectid = OBJECT_ID('YourProc')
I use this:
use YourDB;
SELECT
object_name(object_id),
last_execution_time,
last_elapsed_time,
execution_count
FROM
sys.dm_exec_procedure_stats ps
where
lower(object_name(object_id)) like 'Appl-Name%'
order by 1

How can I get the definition (body) of a trigger in SQL Server?

Unable to find a SQL diff tool that meets my needs, I am writing my own. Between the INFORMATION_SCHEMA and sys tables, I have a mostly-complete working version. But one thing I can't find in the metadata is the definition of a trigger, you know, the actual SQL code. Am I overlooking something?
Thanks.
Thanks, Pete, I didn't know about that!
Scott, I'm working with very basic hosting packages that don't allow remote connections to the DB. I don't know from the specs on RedGate (which I can't afford anyway) whether they provide a workaround for that, and although there are also API's out there (such as the one from Apex), I didn't see the point in investing in a solution that was still going to require more programming on my part. :)
My solution is to drop an ASPX page on the site that acts as a kind of "schema service", returning the collected metadata as XML. I set up a little AJAX app that compares any number of catalog instances to a master and shows the diffs. It's not perfect, but a major step forward for me.
Thanks again!
sp_helptext works to get the sql that makes up a trigger.
The text column in the syscomments view also contains the sql used for object creation.
SELECT
DB_NAME() AS DataBaseName,
dbo.SysObjects.Name AS TriggerName,
dbo.sysComments.Text AS SqlContent
FROM
dbo.SysObjects INNER JOIN
dbo.sysComments ON
dbo.SysObjects.ID = dbo.sysComments.ID
WHERE
(dbo.SysObjects.xType = 'TR')
AND
dbo.SysObjects.Name = '<YourTriggerName>'
For 2005 and 2008 you can use the OBJECT_DEFINITION() function
To expand on SQLMenace's answer, here's a simple query to return all triggers and their definitions from a database:
SELECT
sysobjects.name AS trigger_name,
OBJECT_NAME(parent_obj) AS table_name,
OBJECT_DEFINITION(id) AS trigger_definition
FROM sysobjects
WHERE sysobjects.type = 'TR'
you have various ways to view SQL Server trigger definition.
querying from a system view:
SELECT definition
FROM sys.sql_modules
WHERE object_id = OBJECT_ID('trigger_name');
Or
SELECT OBJECT_NAME(parent_obj) [table name],
NAME [triger name],
OBJECT_DEFINITION(id) body
FROM sysobjects
WHERE xtype = 'TR'
AND name = 'trigger_name';
definition using OBJECT_DEFINITION function:
SELECT OBJECT_DEFINITION(OBJECT_ID('trigger_name')) AS trigger_definition;
definition using sp_helptext stored procedure:
EXEC sp_helptext
'trigger_name';
this query return trigger with its name and body.
Select
[tgr].[name] as [trigger name],
[tbl].[name] as [table name] ,
OBJECT_DEFINITION(tgr.id) body
from sysobjects tgr
join sysobjects tbl
on tgr.parent_obj = tbl.id
WHERE tgr.xtype = 'TR'

Resources