带有表值参数的SQL内联表函数挂起

时间:2015-04-24 10:33:14

标签: sql freeze table-valued-parameters inline-table-function

我编写了一个内联表函数,它可以在我的机器上运行(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时,它也很奇怪,显示锁定这些对象:sysrscolssysrowsetssysallocunitssysprivssysschobjs,{{1 }},syscolparssysxpropssysidxstatssysiscolssysaudactssysobjvaluessyssingleobjrefssysmultiobjrefssysobjkeycryptssyssoftobjrefs(函数名称,有时会显示两次),foo(其中一个表),Nurses(某种属于TVP的索引) ;但并不是所有的时间 - 当我重新运行TT_TableType_2085175E查询时,它们来来去去,有时会降低到上述2中的所有数量。同时,查询窗口继续挂起。无论如何它都不会使服务器过载,我可以通过调用SqlCommand.Cancel()和dm_tran_locks来调用SQL端的会话来轻松取消。

毋庸置疑,与多语句或直接运行相同的查询会立即在所有环境中返回。

0 个答案:

没有答案