我编写了一个内联表函数,它可以在我的机器上运行(Win 7上的SQL 08 R2),但在任何其他环境(Win 2003 Server上的SQL 08 R2)上,即使在最轻的负载下也只是挂起。数据库或服务器设置之间没有区别。
ALTER FUNCTION dbo.Foo
(
@tableParam dbo.TableType READONLY
)
RETURNS TABLE AS RETURN
WITH t AS
(SELECT
rc.ClientId, rc.Type,
f.Id AS NurseId
FROM dbo.PracticeNurses AS pf WITH (NOLOCK)
INNER JOIN @tableParam AS rc ON rc.RowIds = pf.Id
LEFT JOIN dbo.Nurses AS f WITH (NOLOCK) ON f.Id = pf.NurseId)
SELECT DISTINCT '[dbo].[Nurses]' AS T, CAST(t.NurseId AS VARCHAR(300)) AS I, ClientId, Type FROM t
将其更改为执行完全相同操作的多语句函数可立即解决问题 - 适用于所有环境:
ALTER FUNCTION dbo.Foo
(
@rowsClients dbo.TableType READONLY
)
RETURNS @result TABLE
(
T VARCHAR(300),
I VARCHAR(300),
ClientId INT,
Type TINYINT
)
AS
BEGIN
WITH t AS
(SELECT
rc.ClientId, rc.Type,
f.Id AS NurseId
FROM dbo.PracticeNurses AS pf WITH (NOLOCK)
INNER JOIN @tableParam AS rc ON rc.RowIds = pf.Id
LEFT JOIN dbo.Nurses AS f WITH (NOLOCK) ON f.Id = pf.NurseId)
INSERT INTO @result
SELECT DISTINCT '[dbo].[Nurses]' AS T, CAST(t.NurseId AS VARCHAR(300)) AS I, ClientId, Type FROM t
RETURN;
END
表格类型定义如下:
CREATE TYPE dbo.TableType AS TABLE
(
RowIds VARCHAR(300),
Type TINYINT,
ClientId INT
);
调用代码很简单:
DECLARE @t dbo.TableType;
INSERT INTO @t VALUES () ...; -- a few rows, less than 10. same issue without an insert
SELECT * FROM dbo.foo(@t); -- just hangs and does nothing
我现在将其更改为多语句,但显然更倾向于出于性能原因而使用内联版本。我尝试连续运行sp_WhoIsActive
并显示一个奇怪的现象:“TSQL”列在空白和调用查询的文本之间交替。在查询dm_tran_locks
时,它也很奇怪,显示锁定这些对象:sysrscols
,sysrowsets
,sysallocunits
,sysprivs
,sysschobjs
,{{1 }},syscolpars
,sysxprops
,sysidxstats
,sysiscols
,sysaudacts
,sysobjvalues
,syssingleobjrefs
,sysmultiobjrefs
,sysobjkeycrypts
,syssoftobjrefs
(函数名称,有时会显示两次),foo
(其中一个表),Nurses
(某种属于TVP的索引) ;但并不是所有的时间 - 当我重新运行TT_TableType_2085175E
查询时,它们来来去去,有时会降低到上述2中的所有数量。同时,查询窗口继续挂起。无论如何它都不会使服务器过载,我可以通过调用SqlCommand.Cancel()和dm_tran_locks
来调用SQL端的会话来轻松取消。
毋庸置疑,与多语句或直接运行相同的查询会立即在所有环境中返回。