4

好奇之前是否有人遇到过这个问题以及根本原因是什么。问题是在 SQL 2012 中执行包含实际查询计划时发生错误。它可以在 2008 R2 中以任何方式(有或没有计划)工作,并且在没有打开计划的情况下在 2012 年工作。我在针对分区视图测试功能时发现了这一点。

--Setup
USE master
go 

DROP DATABASE Test
GO

CREATE DATABASE Test
GO

USE Test
GO

CREATE TABLE DD (pkID int IDENTITY(1,1), FullDate date);
INSERT INTO DD (FullDate) VALUES ('2013-01-01')
INSERT INTO DD (FullDate) VALUES ('2013-01-02')
INSERT INTO DD (FullDate) VALUES ('2013-01-03')
INSERT INTO DD (FullDate) VALUES ('2013-01-04')
INSERT INTO DD (FullDate) VALUES ('2013-01-05')
GO

CREATE TABLE DC (pkID int IDENTITY(1,1), Filter varchar(32), FilterGroup varchar(32));
INSERT INTO DC (Filter, FilterGroup) VALUES ('one', 'groupone')
INSERT INTO DC (Filter, FilterGroup) VALUES ('two', 'grouptwo')
INSERT INTO DC (Filter, FilterGroup) VALUES ('three', 'groupone')
GO

CREATE TABLE FDA1 (pkID int IDENTITY(1,1), fkpID int, fkCID int, fkDateID int)
INSERT INTO FDA1(fkpID, fkCID, fkDateID) VALUES (1,1,1)
INSERT INTO FDA1(fkpID, fkCID, fkDateID) VALUES (1,2,1)
INSERT INTO FDA1(fkpID, fkCID, fkDateID) VALUES (1,1,3)
INSERT INTO FDA1(fkpID, fkCID, fkDateID) VALUES (1,3,5)
GO

CREATE TABLE FDA2 (pkID int IDENTITY(1,1), fkpID int, fkCID int, fkDateID int)
INSERT INTO FDA2(fkpID, fkCID, fkDateID) VALUES (2,1,2)
INSERT INTO FDA2(fkpID, fkCID, fkDateID) VALUES (2,2,2)
INSERT INTO FDA2(fkpID, fkCID, fkDateID) VALUES (2,1,4)
INSERT INTO FDA2(fkpID, fkCID, fkDateID) VALUES (2,3,5)
GO

CREATE VIEW FDA 
AS
    SELECT pkID, fkpID, fkCID, fkDateID FROM FDA1
    UNION ALL
    SELECT pkID, fkpID, fkCID, fkDateID FROM FDA2
GO

CREATE FUNCTION GetFilter
(
    @pID int
    , @filterGroup varchar(32)
)
RETURNS @Filter TABLE 
(
    CID int
)
AS
BEGIN
    INSERT INTO
        @Filter
    SELECT 
        dc.pkID 
    FROM
        DC dc
    WHERE
        dc.FilterGroup = @filterGroup 
    RETURN
END
GO

CREATE PROC test (@ID int)
AS
BEGIN
    BEGIN TRY
        DECLARE @FilterGroup varchar(32) = 'groupone'

        SELECT
            CAST(MIN(dd.FullDate) As datetime) as ProjectReviewStartDate
        FROM
            dbo.FDA fda
            INNER JOIN dbo.DD dd On fda.fkDateID = dd.pkID 
            INNER JOIN dbo.GetFilter(@ID, @FilterGroup) ctl on fda.fkCID = ctl.CID  
        WHERE
            fda.pkID = @ID 
        OPTION (RECOMPILE);
        RETURN 0;
    END TRY
    BEGIN CATCH

        --Declare variables for error information.
        Declare
            @ErrorMessage nvarchar(max),
            @ErrorSeverity bigint,
            @ErrorState int;

        --Populate error information.
        Select
            @ErrorMessage = ERROR_MESSAGE(),
            @ErrorSeverity = ERROR_SEVERITY(),
            @ErrorState = ERROR_STATE();

        --Re-throw error to calling method.
        RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);

        --Failure
        RETURN -1;
    END CATCH;
END
GO

现在设置完成,让我们运行实际代码,首先“包含实际执行计划”

USE Test
GO

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

DECLARE @id int = 1
DECLARE @tbl table (dt datetime)
DECLARE @findate datetime

INSERT @tbl EXEC test @id

SELECT @findate = dt FROM @tbl
SELECT @findate
GO

您应该收到以下结果:2013-01-01 00:00:00.000。

现在打开包含实际执行计划,您将收到 NULL 结果并看到错误(在 SQL 2012 中):

消息 50000,级别 16,状态 10,过程测试,第 33 行字符串或二进制数据将被截断。

启用包含实际执行计划并从 proc 中删除 Try/Catch 块将删除错误并返回正确的结果。然而,这在 2008R2 中再次运行良好。

有任何想法吗?

谢谢

4

1 回答 1

2

我还没有给你答案,只是你可能遇到了错误的更多弹药。

首先,为了证明这并不RAISERROR具体涉及,将该行更改为:

THROW;

而是返回此错误消息:

消息 8152、级别 16、状态 10、过程测试、第 7 行
字符串或二进制数据将被截断。

所以这表明错误发生在SELECT调用中,TRY/CATCH并且与显示实际计划的组合有关。

接下来,让我们看看元数据描述为存储过程的输出:

SELECT name, system_type_name
  FROM sys.dm_exec_describe_first_result_set_for_object
  (OBJECT_ID('test'), NULL);

结果:

name                    system_type_name
----------------------  ----------------
ProjectReviewStartDate  datetime

现在,如果我们尝试测试您正在运行的批处理的元数据,让我们看看它对元数据的说明(实际上,结果是一条错误消息):

SELECT [error_message]
FROM sys.dm_exec_describe_first_result_set(N'DECLARE @id int = 1
  DECLARE @tbl table (dt datetime)
 DECLARE @findate datetime
 INSERT @tbl 
 EXEC test @id', -1, NULL);

结果:

error_message
----------------------------------------------------------
Incorrect syntax near '-'.
The batch could not be analyzed because of compile errors.

批次中没有-。这是在执行计划关闭的情况下。即使您在上面的批处理中注释掉插入,您也会得到相同的结果。甚至例如:

SELECT error_message
  FROM sys.dm_exec_describe_first_result_set(N'EXEC test 1', -1, NULL);

错误消息变化如此轻微(仔细观察):

error_message
----------------------------------------------------------
Incorrect syntax near '1'.
The batch could not be analyzed because of compile errors.

我们已经删除了任何涉及显示计划或潜在截断的内容,我们仍然可以证明 SQL Server 在为这个简单的批处理编译和/或生成元数据时存在某种问题。

似乎是一个非常简单的重现,并且您有解决方法,但我肯定会在 Connect 上归档

编辑

我看到你提交了一个错误;任何可以重现这种情况的人都应该投票并确认重现:

http://connect.microsoft.com/SQLServer/feedback/details/785151/show-actual-query-plan-causes-error

于 2013-04-19T17:44:04.150 回答