我正在尝试为我的数据库中的一些存储过程生成使用情况报告。视图视图sys.dm_exec_procedure_stats包含我需要的一些内容,所以我决定从这里开始。
SQL Server 按对象 ID 键控过程元数据。我只知道过程名称,所以首先我必须使用OBJECT_ID函数将名称映射到 ID 。
有几个程序要检查,所以我想在处理它们之前把它们的名字放在一个临时表中。
我认为从临时表中的计算列中获取对象 id 会很可爱,所以我创建了一个这样的表:
USE msdb;
GO
CREATE TABLE #procs (
name SYSNAME,
[object_id] AS OBJECT_ID(name)
);
INSERT INTO #procs (name) VALUES ('dbo.sp_send_dbmail');
INSERT INTO #procs (name) VALUES ('dbo.sp_add_job');
INSERT INTO #procs (name) VALUES ('dbo.sp_start_job');
有了该表,获取执行计数的明显方法如下所示:
SELECT #procs.name, execution_count
FROM sys.dm_exec_procedure_stats AS procstats
INNER JOIN #procs ON #procs.[object_id] = procstats.[object_id]
ORDER BY execution_count DESC;
但它返回一个空的结果集!
此查询显示结果集为空的原因:
SELECT name, [object_id]
FROM #procs;
object_id 列是 NULL,所以内连接不会产生任何行:
name object_id
-------------------- -----------
dbo.sp_send_dbmail NULL
dbo.sp_add_job NULL
dbo.sp_start_job NULL
这并不是临时表的计算列被破坏。如果我添加一个计算列来反转名称,当我从中选择时它会产生正确的值:
ALTER TABLE #procs ADD reverse_name AS REVERSE(name);
SELECT name, [object_id], reverse_name
FROM #procs;
结果:
name object_id reverse_name
-------------------- ----------- ---------------------
dbo.sp_send_dbmail NULL liambd_dnes_ps.obd
dbo.sp_add_job NULL boj_dda_ps.obd
dbo.sp_start_job NULL boj_trats_ps.obd
为什么 OBJECT_ID 在这里返回 NULL?
表中计算列中提到的元数据函数
#temp
将引用tempdb.sys.objects
,而不是yourdatabase.sys.objects
,因为表是在tempdb
. 尝试将数据库前缀添加到插入中,这将使OBJECT_ID
go 在正确的位置找到它:结果:
你正在做一些过于过于复杂的琐碎事情。删除计算列,
OBJECT_ID
显式插入。发生的情况是您失去了
OBJECT_ID
对评估位置(在哪个数据库上下文中)的控制。OBJECT_ID
将在不同的 DBS 中为相同的名称返回不同的值,或者对于与当前执行上下文 (db) 不匹配的名称可能返回 NULL。通过将评估添加到#temp
表格中,您无法确定评估发生在哪里。在tempdb
吗?在msdb
?在当前数据库中?嗯,它看起来不像你预期的那样,那是肯定的......抛弃花哨的聪明,坚持KISS。
接下来,修复您的
`JOIN #procs ON #procs.[object_id] = procstats.[object_id]
, 不正确。您需要加入object_id
和database_id
。