SQL Cause of table updates - sql-server

Is there a way to determine how a table is updated? I have a table that is being updated and I can't figure out how; by an agent job? ssis package? trigger?
I've queried against dm_exec_query_stats and dm_exec_sql_text to determine the statement that is being run, but I don't know where it's being executed from.
SELECT SQL_HANDLE, deqs.plan_handle, deqs.last_execution_time,
dest.text
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest
WHERE dest.text LIKE '%Update%'
ORDER BY deqs.last_execution_time desc

Use this query for any dependent stored procedure that has insert/update/select queries for a particular table . Alternatively if you have a trigger on the table which captures inserted datetime , you can analyse by checking current running queries.
It would need a lot of digging of any SSIS jobs are scheduled for table update, usually most updates are done through SP's. This below query is only a quick check.
SELECT DISTINCT QUOTENAME(OBJECT_SCHEMA_NAME(referencing.object_id)) + '.' + QUOTENAME(OBJECT_NAME(referencing.object_id)) AS SprocName
,QUOTENAME(OBJECT_SCHEMA_NAME(referenced.object_id)) + '.' + QUOTENAME(OBJECT_NAME(referenced.object_id)) AS ReferencedObjectName
,referenced.type_desc AS ReferencedObjectType
FROM sys.sql_dependencies d
INNER JOIN sys.procedures referencing ON referencing.object_id = d.object_id
INNER JOIN sys.objects referenced ON referenced.object_id = d.referenced_major_id
WHERE referencing.type_desc = 'SQL_STORED_PROCEDURE'
AND referenced.type_desc = 'USER_TABLE'
ORDER BY SprocName
,ReferencedObjectName

You can find out if your table is referenced in any stored procedure, function, view or triggger with this code
suppose the table you are looking for is called tblMyTable
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc,
m.*
FROM sys.sql_modules m
INNER JOIN sys.objects o ON m.object_id = o.object_id
WHERE m.definition Like '%tblMyTable%';
This will return any stored procedure, function, view or triggger that has tblMyTable in its text, so even if it only just reads from it.
So you need to check each one to see if its updating or not.
Yes its some work, but at least it gives you a change to find out if the update is coming from any object in your database.
If this returns nothing then you know that you have to search in your client software.

I know this may not be a good way to do this and I might get burned for this but, here's what I did...
I executed an open transaction against the table; locking it.
BEGIN TRANSACTION
SELECT
TOP 1 *
FROM *tbl*
I then queried dm_exec_requests to find the session_id that is being run
SELECT
sqltext.TEXT,
req.session_id
FROM sys.dm_exec_requests req
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext
I then queried dm_exec_sessions to find the host_name and program_name that is running that session.
SELECT
host_name,
login_time,
program_name
FROM sys.dm_exec_sessions
WHERE session_id = 184
I was able to determine that the culprit was an SSIS package hosted on a different server. Close the locking transaction
Thanks everyone for all the help

Related

How to check if data has changed in database

In order to create a Dashboard I need to work on a database that I do not have information about. The data in the DataBase is updated through a particular management interface and I do not know where it is updated on the DB. Is there a way to check for data updates without the tables names or columns names?
Thanks
I agree that knowing nothing about the database will not get you very far, but you can get some information about table updates without knowing what you're looking for. Whether or not it's useful is a different question.
The included code leverages sys.dm_db_index_usage_stats to identify the last time a user update was performed on the table. This works for heaps as well as indexed tables and the user_update value includes inserts, deletes, and updates. The sys.dm_db_index_usage_stats view will include information only for tables that have been interacted. To work around that I UNION ALL with a second query to get the relevant object information for tables that aren't found in sys.dm_db_index_usage_stats. This gives a complete view of the table objects regardless of whether or not they've been used since the service started. You may not care about that at all and could strip it out.
Again, this may not be helpful, but your question was just "Is there a way to check for data updates without the tables names or columns names?" and the answer to that specific question is yes.
Caveats:
The user_update value is simply an incrementing counter of update actions. This will not let you know what the update was or how many updates have occured since X point in time, but it will let you know the last time a table was updated.
This information does not persist beyond a service restart, so if a table was updated right before a restart, you wouldn't know.
The provided script is database specific, meaning it only returns information about the datbase it runs in. You could use something like sp_MSforeachdb to run against everything though.
And the code...
SELECT * FROM
(
SELECT
##servername as servername
, DB_NAME(database_id) as DatabaseName
, u.object_id
, SchemaName = OBJECT_SCHEMA_NAME(u.object_id, database_Id)
, TableName = OBJECT_NAME(u.object_id, database_id)
, Writes = SUM(user_updates)
, LastUpdate = CASE WHEN MAX(u.last_user_update) IS NULL THEN CAST('17530101' AS DATETIME) ELSE MAX(u.last_user_update) END
FROM sys.dm_db_index_usage_stats u
JOIN sys.indexes i
ON u.index_id = i.index_id
AND u.object_id = i.object_id
WHERE u.database_id = DB_ID()
GROUP BY database_id, u.object_id
UNION ALL
SELECT
##servername as servername
, DB_NAME() as DatabaseName
, o.object_id
, OBJECT_SCHEMA_NAME(o.object_id, db_id())
, object_name(o.object_id, db_id())
, 0
, CAST('17530101' AS DATETIME)
FROM sys.indexes i
JOIN sys.objects o ON i.object_id = o.object_id
WHERE o.type_desc in ('user_table')
and i.index_id NOT IN (select s.index_id from sys.dm_db_index_usage_stats s where s.object_id=i.object_id
and i.index_id=s.index_id and database_id = db_id(db_name()) )
) AS temp
ORDER BY writes DESC

How to check a database in SQL to make sure that all of its tables are in use?

I was assigned to see if all of the current tables in a database are used and if not to drop them. These are the steps I have taken so far:
Searched tables names in the program that uses that database to see if a query has been made in the program based on those tables names.
Investigated if a table primary key has been used in any other places such as view or table (Connectivity with other used tables). I used:
SELECT
t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM
sys.tables AS t
INNER JOIN
sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE
c.name LIKE 'DeflectionId' -- write the column you search here
ORDER BY
schema_name, table_name;
Searched inside all of the stored procedure texts to see if a table name has been used inside them:
SELECT DISTINCT
o.name AS Object_Name,
o.type_desc
FROM
sys.sql_modules m
INNER JOIN
sys.objects o ON m.object_id = o.object_id
WHERE
m.definition LIKE '%\[Test_Results_LU\]%' ESCAPE '\';
or
SELECT name
FROM sys.procedures
WHERE Object_definition(object_id) LIKE '%Test_Results_LU%'
(from this link: Search text in stored procedure in SQL Server )
Used Object Explorer view to see if a table with the similar/same name and size exists in the database.
Do you think there are other ways that I can use to investigate it better?
Are these steps efficient at all? How would you do it?
Those are all reasonable things to check. One more thing to do would be to turn on profiling or auditing, depending on your SQL server version, and actually monitor for the tables being used for a reasonable time period. You may not be able to do that with a production system, and it's still not 100% guaranteed - what if there's an important table that's only queried once a year?
https://dba.stackexchange.com/questions/40960/logging-queries-and-other-t-sql
https://learn.microsoft.com/en-us/sql/relational-databases/security/auditing/view-a-sql-server-audit-log?view=sql-server-2017
One other suggestion before dropping the tables is to explicitly remove access to them (either with DENY/REVOKE or rename them to table-name_purge) for a week or two and see if anyone complains. If they don't, then it's probably safe to make a backup and then drop them.
A couple of other places to check. Both of these rely on data that is
cached automatically by the system
not persisted between restarts
can be dropped at any time.
so absence from these results does not prove that the table is not used but you may find evidence that a table definitely is in use.
SELECT [Schema] = OBJECT_SCHEMA_NAME(object_id),
[ObjectName] = OBJECT_NAME(object_id),
*
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID()
And in the plan cache
USE YourDB
DROP TABLE IF EXISTS #cached_plans, #plans, #results
DECLARE #dbname nvarchar(300) = QUOTENAME(DB_NAME());
SELECT dm_exec_query_stats.creation_time,
dm_exec_query_stats.last_execution_time,
dm_exec_query_stats.execution_count,
dm_exec_query_stats.sql_handle,
dm_exec_query_stats.plan_handle
INTO #cached_plans
FROM sys.dm_exec_query_stats;
WITH distinctph
AS (SELECT DISTINCT plan_handle
FROM #cached_plans)
SELECT query_plan,
plan_handle
INTO #plans
FROM distinctph
CROSS APPLY sys.dm_exec_query_plan(plan_handle);
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT cp.*,
st.text,
[Database] = n.value('#Database', 'nvarchar(300)'),
[Schema] = n.value('#Schema', 'nvarchar(300)'),
[Table] = n.value('#Table', 'nvarchar(300)')
INTO #results
FROM #cached_plans cp
JOIN #plans p
ON cp.plan_handle = p.plan_handle
CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
CROSS APPLY query_plan.nodes('//Object[#Database = sql:variable("#dbname") and #Schema != "[sys]"]') qn(n);
SELECT *
FROM #results

Using SQL Server - is there a way to query 'Create view' SQL

I want to know if a certain table dbo.person is being used in any of the database views in my database. There are a lot of views in this database.
I could right click each view "Script View as --> CREATE To" to see the SQL that was used to build this view but this will take a long time.
I am wondering if there is any way to query all of these "create view as" scripts to see if any of them mention my table dbo.person.
I hope this is clear.
You can query the system catalog for views (and use sql_modules to get the view definition) then use the system view sys.sql_expression_dependencies to find which of these views reference dbo.Person:
SELECT ViewName = QUOTENAME(OBJECT_SCHEMA_NAME(v.[object_id])) + '.' + QUOTENAME(v.Name),
m.[Definition]
FROM sys.views AS v
INNER JOIN sys.sql_modules AS m
ON m.[object_id] = v.[object_id]
WHERE EXISTS
( SELECT 1
FROM sys.sql_expression_dependencies AS d
WHERE d.Referenced_id = OBJECT_ID(N'dbo.Person', 'U')
AND v.[object_id] = d.referencing_id
)
ORDER BY ViewName;
There are some small issues with sys.sql_expression_dependencies, but I would still be more inclined to use this than to search for '%person%', since this could bring back 10s, or 100s of extra results, any time a table that contains person (e.g. dbo.PersonAddress) is referenced, or person is used as an alias (SELECT Forename + surname AS Person) etc. It really depends whether you are looking for something that is going to be accurate most of the time, but may, on occasion miss a reference, or whether you need a catch all solution that will bring back extra results.
You could try
select * from INFORMATION_SCHEMA.VIEWS
where VIEW_DEFINITION like '%Person%'
You might need to change the WHERE to dbo.person or [Person]
For a more detailed string search on SQL Server database object definitions please refer to SQL Object Where Used List script
You can simply call like
exec SearchInObjectsText 'name'
and it will return procedures, functions, views, etc where the text "name" is used
I know this doesn't answer the question directly, but it answers the need. I use a third party add-in called SQLSearch from redgate. It's free and I'm not an employee, so this isn't a "plug" of any kind.
I normally use this SQL to look in definitions. I didn't filter on VIEWS just in case it is used somewhere else.
SELECT
so.name, so.type, sm.Definition
FROM
sys.objects AS so INNER JOIN sys.sql_modules AS sm ON so.object_id = sm.object_id
WHERE
sm.Definition LIKE N'%dbo.person%'
ORDER BY so.name
Please query Information_Schema.View_Table system views
select * from INFORMATION_SCHEMA.VIEW_TABLE_USAGE where TABLE_NAME = 'Emp'
Try this
SELECT DISTINCT m.definition, o.name AS Object_Name,o.type_desc
FROM sys.sql_modules m
INNER JOIN sys.objects o
ON m.object_id=o.object_id
WHERE m.definition Like '%person%'
and type_desc = 'VIEW'

Query to find Table objects dependent on a Table in SQL Server 2008

I searched online to find a solution to the aforementioned topic but failed to get something that works for me. I only want a SQL statement that will query a database and bring out tables that are dependent on a particular table. I tried the sp_depends approach but it only brought out stored procedures and check constraints in the result set but no tables.
I stumbled on sys.sql_expression_dependenciesbut I discovered it doesn't work for SQL Server 2008. Please I need some help to get this done.
Many thanks.
Simply we can do this In SQL server management studio Right-click on a table and choose 'View Dependencies'.
By using query
Select
S.[name] as 'Dependent_Tables'
From
sys.objects S inner join sys.sysreferences R
on S.object_id = R.rkeyid
Where
S.[type] = 'U' AND
R.fkeyid = OBJECT_ID('tablename')
Another method
SELECT DISTINCT name, so.type
FROM sys.objects AS so
INNER JOIN sys.sql_expression_dependencies AS sed
ON so.object_id = sed.referencing_id
WHERE sed.referenced_id = OBJECT_ID('[tablename]');
Second method selects Procedures, views too.
I found a way around it and I give the credit to Arunprasanth KV for giving a response that guided me to the solution. After studying the schema of the tables properly, the following query gave me exactly what I wanted:
Select
S.[name]
From
sys.objects S inner join sys.sysreferences R
on S.object_id = R.fkeyid
Where
S.[type] = 'U' AND
R.rkeyid = OBJECT_ID('TableName')
GO
Use dm_sql_referencing_entities system view which will give you objects dependent on the table
SELECT referencing_schema_name,
referencing_entity_name,
referencing_id,
referencing_class_desc
FROM sys.Dm_sql_referencing_entities ('schema.Tablename', 'OBJECT')

TSQL query to find un-used stored procedures

I am trying to track down all stored procedures in a database that have never been used, or that have not been used in many months.
I would like to find a query to show all the stored procedures that are not in use so that those stored procedures can be analyzed to determine if they can be removed.
I am familiar with sys.procedures, but don't know how to determine if a procedure is in use or not.
SELECT *
FROM sys.procedures;
Using SQL Server 2008 R2.
UPDATE UPDATE UPDATE
Using the query from Aaron Bertrand below, slightly modified, this is what I ended up using, and it was perfect.
SELECT p.*
FROM sys.procedures AS p
LEFT JOIN sys.dm_exec_procedure_stats AS s ON s.[object_id] = p.[object_id]
WHERE s.object_id IS NULL;
Thanks for the hlep.
DMVs will record stats for procedures, but they only possibly go as far back as the last restart (and often not that far, depending on how long a plan lives in cache):
SELECT * FROM sys.dm_exec_procedure_stats AS s
INNER JOIN sys.procedures AS p
ON s.[object_id] = p.[object_id]
ORDER BY p.name;
So if your system has only been up for a short time, this is not a reliable measure. The link #Siva points out is useful as well for some other ideas. Unfortunately SQL Server doesn't really track this for you overall so unless you add tracing or logging you are stuck with the trust you place in the DMV...
EDIT it was a good point, I was solving for the procedures that have run. Instead you may want this:
SELECT sc.name, p.name
FROM sys.procedures AS p
INNER JOIN sys.schemas AS sc
ON p.[schema_id] = sc.[schema_id]
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS st
ON p.[object_id] = st.[object_id]
WHERE st.[object_id] IS NULL
ORDER BY p.name;
Or you may want to also include procedures that have run as well, but order them by when they last ran:
SELECT sc.name, p.name
FROM sys.procedures AS p
INNER JOIN sys.schemas AS sc
ON p.[schema_id] = sc.[schema_id]
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS st
ON p.[object_id] = st.[object_id]
ORDER BY st.last_execution_time, p.name;
This will order first the procedures that haven't run since a restart, then the rest by when they were executed last, oldest first.
Here's a variation on the accepted answer that was the most useful for me:
SELECT sc.NAME + '.' + p.NAME [Procedure]
,s.last_execution_time
FROM sys.procedures AS p
LEFT JOIN sys.dm_exec_procedure_stats AS s ON p.[object_id] = s.[object_id]
INNER JOIN sys.schemas sc ON p.schema_id = sc.schema_id
ORDER BY s.last_execution_time
,sc.NAME
,p.NAME
The modifications display the last execution time and include the procedure's schema.
For some reason, my dm_exec_procedure_stats view clears itself out through the day. So I just ran it right now and the earliest execution times are from this morning, but I know we didn't restart SQL this morning or anything.
Anyway, I wanted to create a proc that I could put into a job to run every hour and capture which procs had run recently. Here is what I did:
Created a table to log the procs that get executed and their first and last execution times.
create table ProcsThatExecute (procName varchar(500), firstExecutionTime datetime, lastExecutionTime datetime)
Created a procedure that inserts or updates the ProcsThatExecute table. Run this every hour in a job and after a few days or weeks or months you have a log of which procs get used:
alter procedure LogProcsThatExecute as begin
--If they don't already exist in this table, add them.
insert into ProcsThatExecute(procName, firstExecutionTime, lastExecutionTime)
SELECT p.NAME ProcName, s.last_execution_time, null
FROM sys.procedures AS p
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS s ON p.[object_id] = s.[object_id]
where not exists (
select 1 from ProcsThatExecute pte where pte.procName = p.name
) and last_execution_time is not null
--If they do exist in this table, update the last execution time.
update ProcsThatExecute set lastExecutionTime = s.last_execution_time
from ProcsThatExecute pte
inner join sys.procedures AS p on pte.procName = p.name
LEFT OUTER JOIN sys.dm_exec_procedure_stats AS s ON p.[object_id] = s.[object_id]
where s.last_execution_time is not null
end

Resources