显示实际查询计划会导致错误?

时间:2013-04-19 16:34:10

标签: sql-server tsql

如果有人之前遇到过这个问题并且根本原因是什么,那就很好奇。问题是在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中):

Msg 50000,Level 16,State 10,Procedure test,Line 33 字符串或二进制数据将被截断。

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

有什么想法吗?

由于

1 个答案:

答案 0 :(得分:2)

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

首先,要证明这不涉及RAISERROR,请将该行更改为:

THROW;

返回此错误消息:

  

Msg 8152,Level 16,State 10,Procedure test,Line 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.

我们删除了showplan或潜在截断的任何参与,我们仍然可以证明SQL Server在编译和/或生成这个简单批处理的元数据方面存在某种问题。

似乎是一个非常简单的复制品,你有办法,但是I would definitely file this on Connect

修改

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

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