CLR 过程未在进程 SQL 服务器中列出
CLR Procedure Not list in processes SQL Server
我创建了一个 CLR 过程来下载电子邮件文件。它工作得很好,问题是当它是 运行 时,当我查询服务器进程时它没有被列出。
有人知道在 sql 服务器进程中获取它的方法吗?
我正在使用下面的查询
exec dbo.sp_download_files_mail
如果您希望通过 sys.dm_exec_requests.plan_handle
在 sys.dm_exec_sql_text
中看到 exec dbo.sp_download_files_mail
,那么这可能不会发生。当您使用 EXEC
时,它会创建一个可能是不同执行计划的子流程。在 SQLCLR 的情况下,SQL 服务器无法洞察正在发生的事情,除非您使用 SqlConnection
执行 T-SQL,然后您将获得计划SQL 在 SQLCLR 对象中执行,而不是 SQLCLR 对象本身的计划。当你正在执行一个 SQLCLR 对象并且它没有执行任何 T-SQL 语句时,那么 sql_handle
和 plan_handle
值都是空的: 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
但是,您可以看到 SQLCLR 对象出现在从 sys.dm_exec_cached_plans
返回的 plan_handle
值中。 SQLCLR 对象在执行时似乎确实出现在此 DMV 中,但由于此 DMV 报告缓存的对象,一旦 SQLCLR 对象完成,它不一定会被删除。因此,您不能使用此 DMV 来指示对象的 current 运行 状态。 sys.dm_exec_cached_plans
中报告的 plan_handle
值也不会显示在 sys.dm_exec_requests
中,而它是 运行.
您可以自己测试此行为,方法是创建一个 SQLCLR 存储过程或 SQLCLR 标量用户定义函数,它们只会调用 System.Threading.Thread.Sleep()
至少 30 秒.如果你不想创建这个,预制的 SQLCLR UDF – DB_WaitForDelay – 存在于 [=36= 的免费版本中] SQLCLR 库(我创建的)并且是我在下面的示例代码中使用的库。
在 SQL Server Management Studio (SSMS) 中,打开两个查询选项卡并粘贴以下内容:
选项卡 1
EXEC [SQL#].[DB_WaitForDelay] 30000, 1;
选项卡 2
SELECT txt.*, req.*
FROM sys.dm_exec_requests req
OUTER APPLY sys.dm_exec_sql_text(req.[plan_handle]) txt
WHERE req.[session_id] = <session_id_of_Tab1>;
DBCC INPUTBUFFER(<session_id_of_Tab1>);
SELECT txt.*, cp.*
FROM sys.dm_exec_cached_plans cp
OUTER APPLY sys.dm_exec_sql_text(cp.[plan_handle]) txt
WHERE cp.[cacheobjtype] LIKE N'CLR%';
在 Tab 2 查询中替换了“<session_id_of_Tab1>
”的两个实例后,执行 Tab 1查询,然后返回 Tab 2 并执行该批查询。
如果您真的需要知道此 SQLCLR 对象是否正在执行 ,因为它正在执行 ,那么您将不得不按照使用 [= =17=] 和 Context Connection = true;
的 ConnectionString 然后执行(在 SQLCLR 对象的开头)类似 SET CONTEXT_INFO 0x1234;
的东西(假设您还没有使用 CONTEXT_INFO
为别的)。在 SQLCLR 对象的末尾,为 SET CONTEXT_INFO 0x00;
执行第二个 SqlCommand
以将其清除。
这种方法允许您使用以下查询来确认它当前是 运行:
SELECT req.*
FROM sys.dm_exec_requests req
WHERE req.[context_info] = 0x1234;
此外,在存储过程名称前加上 sp_
前缀是一种相当糟糕的做法,因为这会导致 SQL 服务器首先签入 [master]
对象,然后 then 当前数据库。使用 spDownloadEmailFiles
之类的东西更好,尽管仍然没有真正好的理由在存储过程/函数/Table/视图名称前加上任何东西。
我创建了一个 CLR 过程来下载电子邮件文件。它工作得很好,问题是当它是 运行 时,当我查询服务器进程时它没有被列出。
有人知道在 sql 服务器进程中获取它的方法吗?
我正在使用下面的查询
exec dbo.sp_download_files_mail
如果您希望通过 sys.dm_exec_requests.plan_handle
在 sys.dm_exec_sql_text
中看到 exec dbo.sp_download_files_mail
,那么这可能不会发生。当您使用 EXEC
时,它会创建一个可能是不同执行计划的子流程。在 SQLCLR 的情况下,SQL 服务器无法洞察正在发生的事情,除非您使用 SqlConnection
执行 T-SQL,然后您将获得计划SQL 在 SQLCLR 对象中执行,而不是 SQLCLR 对象本身的计划。当你正在执行一个 SQLCLR 对象并且它没有执行任何 T-SQL 语句时,那么 sql_handle
和 plan_handle
值都是空的: 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
但是,您可以看到 SQLCLR 对象出现在从 sys.dm_exec_cached_plans
返回的 plan_handle
值中。 SQLCLR 对象在执行时似乎确实出现在此 DMV 中,但由于此 DMV 报告缓存的对象,一旦 SQLCLR 对象完成,它不一定会被删除。因此,您不能使用此 DMV 来指示对象的 current 运行 状态。 sys.dm_exec_cached_plans
中报告的 plan_handle
值也不会显示在 sys.dm_exec_requests
中,而它是 运行.
您可以自己测试此行为,方法是创建一个 SQLCLR 存储过程或 SQLCLR 标量用户定义函数,它们只会调用 System.Threading.Thread.Sleep()
至少 30 秒.如果你不想创建这个,预制的 SQLCLR UDF – DB_WaitForDelay – 存在于 [=36= 的免费版本中] SQLCLR 库(我创建的)并且是我在下面的示例代码中使用的库。
在 SQL Server Management Studio (SSMS) 中,打开两个查询选项卡并粘贴以下内容:
选项卡 1
EXEC [SQL#].[DB_WaitForDelay] 30000, 1;
选项卡 2
SELECT txt.*, req.*
FROM sys.dm_exec_requests req
OUTER APPLY sys.dm_exec_sql_text(req.[plan_handle]) txt
WHERE req.[session_id] = <session_id_of_Tab1>;
DBCC INPUTBUFFER(<session_id_of_Tab1>);
SELECT txt.*, cp.*
FROM sys.dm_exec_cached_plans cp
OUTER APPLY sys.dm_exec_sql_text(cp.[plan_handle]) txt
WHERE cp.[cacheobjtype] LIKE N'CLR%';
在 Tab 2 查询中替换了“<session_id_of_Tab1>
”的两个实例后,执行 Tab 1查询,然后返回 Tab 2 并执行该批查询。
如果您真的需要知道此 SQLCLR 对象是否正在执行 ,因为它正在执行 ,那么您将不得不按照使用 [= =17=] 和 Context Connection = true;
的 ConnectionString 然后执行(在 SQLCLR 对象的开头)类似 SET CONTEXT_INFO 0x1234;
的东西(假设您还没有使用 CONTEXT_INFO
为别的)。在 SQLCLR 对象的末尾,为 SET CONTEXT_INFO 0x00;
执行第二个 SqlCommand
以将其清除。
这种方法允许您使用以下查询来确认它当前是 运行:
SELECT req.*
FROM sys.dm_exec_requests req
WHERE req.[context_info] = 0x1234;
此外,在存储过程名称前加上 sp_
前缀是一种相当糟糕的做法,因为这会导致 SQL 服务器首先签入 [master]
对象,然后 then 当前数据库。使用 spDownloadEmailFiles
之类的东西更好,尽管仍然没有真正好的理由在存储过程/函数/Table/视图名称前加上任何东西。