Sql server 如何判断数据库表是否正在被访问?想要像“a”这样的东西吗;选择触发器";

Sql server 如何判断数据库表是否正在被访问?想要像“a”这样的东西吗;选择触发器";,sql-server,database-design,sql-server-2008,clustered-index,Sql Server,Database Design,Sql Server 2008,Clustered Index,我有一个非常大的数据库,有数百个表,经过多次产品升级,我确信其中一半不再被使用。如何判断是否正在从中主动选择表?我不能只使用探查器——我不仅想观察几天以上,而且还有数千个存储过程,而且探查器不会将SP调用转换为表访问调用 我唯一能想到的是在感兴趣的表上创建聚集索引,然后监视sys.dm_db_index_usage_stats,查看聚集索引上是否有任何搜索或扫描,这意味着表中的数据已加载。然而,在每个表上添加聚集索引是一个坏主意(出于各种原因),因为这实际上是不可行的 我还有其他选择吗?我一直想

我有一个非常大的数据库,有数百个表,经过多次产品升级,我确信其中一半不再被使用。如何判断是否正在从中主动选择表?我不能只使用探查器——我不仅想观察几天以上,而且还有数千个存储过程,而且探查器不会将SP调用转换为表访问调用

我唯一能想到的是在感兴趣的表上创建聚集索引,然后监视
sys.dm_db_index_usage_stats
,查看聚集索引上是否有任何搜索或扫描,这意味着表中的数据已加载。然而,在每个表上添加聚集索引是一个坏主意(出于各种原因),因为这实际上是不可行的

我还有其他选择吗?我一直想要一个像“选择触发器”这样的功能,但可能还有其他原因导致SQLServer没有这个功能

解决方案:

谢谢你,雷姆斯,为我指明了正确的方向。使用这些列,我创建了下面的SELECT,它正是我想要的

  WITH LastActivity (ObjectID, LastAction) AS 
  (
       SELECT object_id AS TableName,
              last_user_seek as LastAction
         FROM sys.dm_db_index_usage_stats u
        WHERE database_id = db_id(db_name())
        UNION 
       SELECT object_id AS TableName,
              last_user_scan as LastAction
         FROM sys.dm_db_index_usage_stats u
        WHERE database_id = db_id(db_name())
        UNION
       SELECT object_id AS TableName,
              last_user_lookup as LastAction
         FROM sys.dm_db_index_usage_stats u
        WHERE database_id = db_id(db_name())
  )
  SELECT OBJECT_NAME(so.object_id) AS TableName,
         MAX(la.LastAction) as LastSelect
    FROM sys.objects so
    LEFT
    JOIN LastActivity la
      on so.object_id = la.ObjectID
   WHERE so.type = 'U'
     AND so.object_id > 100
GROUP BY OBJECT_NAME(so.object_id)
ORDER BY OBJECT_NAME(so.object_id)

对于SQLServer2008,您应该看一看。这允许您审核许多内容,包括表上的选择和向文件或事件日志报告。

Re:Profiler,如果您监视,它将捕获存储过程中执行的所有语句,以便捕获存储过程中的表访问。如果不是所有内容都经过存储过程,则可能还需要该事件

将有大量的事件,因此由于跟踪的大小,很长一段时间跟踪可能仍然不实用。但是,您可以应用筛选器,例如,其中TextData包含要检查的表的名称。您可以提供一个表名列表,以便在任何时候进行筛选,并逐步进行筛选。因此,如果这些表都未被访问,则不应获取任何跟踪事件

即使你觉得这对你来说不是一个合适/可行的方法,我认为它值得扩展


另一个解决方案是对源代码进行全局搜索,以查找表的引用。您可以查询存储过程定义以检查给定表的匹配项,也可以只生成一个完整的数据库脚本并查找表名的数据库脚本。

我曾考虑过使用不同表的用户权限,但后来我记得您可以使用登录触发器打开跟踪,您可能会从中受益:

CREATE OR REPLACE TRIGGER SYS.ON_LOGON_ALL

AFTER LOGON ON DATABASE
WHEN (

USER 'MAX'

)
BEGIN

EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE';

--EXECUTE IMMEDIATE 'alter session set events ''10046 trace name context forever level 12''';

EXCEPTION

WHEN OTHERS THEN

NULL;

END;

/

然后您可以检查跟踪文件。

查看。last_user_xxx列将包含上次从用户请求访问表的时间。此表在服务器重新启动后重置其跟踪,因此您必须让它运行一段时间,然后才能依赖其数据。

此解决方案比上述解决方案更适合我。但是,仍然需要指出的是,服务器也没有重新启动,但仍然可以让您很好地了解未使用的表

SELECT [name]
      ,[object_id]
      ,[principal_id]
      ,[schema_id]
      ,[parent_object_id]
      ,[type]
      ,[type_desc]
      ,[create_date]
      ,[modify_date]
      ,[is_ms_shipped]
      ,[is_published]
      ,[is_schema_published]
  FROM [COMTrans].[sys].[all_objects]
  where object_id not in (
select object_id from sys.dm_db_index_usage_stats

)
and type='U'
order by name

以下查询使用查询计划缓存查看缓存中的任何现有计划中是否存在对表的引用。这并不能保证100%准确(因为如果存在内存限制,查询计划将被清除),但可以用来了解表的使用情况

SELECT schema_name(schema_id) as schemaName, t.name as tableName,
    databases.name,
dm_exec_sql_text.text AS TSQL_Text,
dm_exec_query_stats.creation_time, 
dm_exec_query_stats.execution_count,
dm_exec_query_stats.total_worker_time AS total_cpu_time,
dm_exec_query_stats.total_elapsed_time, 
dm_exec_query_stats.total_logical_reads, 
dm_exec_query_stats.total_physical_reads, 
dm_exec_query_plan.query_plan
FROM sys.dm_exec_query_stats 
CROSS APPLY sys.dm_exec_sql_text(dm_exec_query_stats.plan_handle)
CROSS APPLY sys.dm_exec_query_plan(dm_exec_query_stats.plan_handle)
INNER JOIN sys.databases ON dm_exec_sql_text.dbid = databases.database_id
RIGHT JOIN sys.tables t (NOLOCK) ON cast(dm_exec_query_plan.query_plan as varchar(max)) like '%' + t.name + '%'

+1用于源代码搜索。一些应用程序具有非常不常用的功能,这些功能可能永远不会被分析/审核捕获。确保的唯一方法是实际检查使用数据库的程序!是的。我更相信源代码搜索(只要你检查所有的源代码!),因为这不涉及监视表上的实际点击,这可能很少见/需要很长时间来标记(你监视多长时间?!)。与此数据库相反的应用程序执行了足够多的特殊SQL,因此存储的过程代码搜索不会捕获所有内容-过程主要用于报告和计划的内容。不过,我喜欢这一次-我从未意识到“StmtCompleted”@rwmnau的SP和SQL版本之间的区别:如果它使用大量特殊SQL,那么在源代码中查找表引用应该更容易,不是吗?是和否-我们有SPs和报告的代码,但该应用程序是专有的,而且我没有访问源代码的权限。我们已经有足够长的时间了,我们非常清楚它是如何工作的,但是我不能检查代码来确定。我的观点是,我不能只在SP代码上进行syscomments搜索来查找表名,因为该应用程序会执行大量不会在SP中显示的临时操作。等等,这有我认为的那么棒吗?我将进行一些测试,但似乎我可以监视表上的“堆”虚拟索引以进行任何查找/扫描/查找,这正好告诉了我想要知道的内容。先生,如果是这样的话,你就是我的英雄。它做你认为它做的事情,而且更多。您可以区分未使用的表(0堆或1个聚集索引)和从未使用过的非聚集索引,以便丢弃不必要的非聚集索引。请记住,当服务器重新启动时它会重置(实际上,当数据库联机时,它会为该数据库重置,详细信息…)。我会用我用你的技巧开发的神奇查询来更新这个问题,但它非常壮观。记住,暂时不使用并不意味着没有使用。年度报告每年只能运行一次。支持这些不常见任务的表在其余时间可能看不到很多操作(或任何操作)。这一点很好。事实证明,数据库并没有像我预期的那样“未使用”,而且由于我们的服务器从10月份开始启动,我们有一个相当可靠的活动快照,包括到年底。再次感谢您的帮助!有没有办法在服务器关闭时将这些数据捕获到表中?这将允许长期跟踪。好问题。只为任何人