Dm_exec_describe_first_result_set_for_object возвращает нули в итерационных ctes - PullRequest
0 голосов
/ 28 августа 2018

Использование: SQL SERVER 2016/2017

В настоящее время я использую sys.dm_exec_describe_first_result_set_for_object для получения выходных определений для большого количества процедур. Я вижу некоторые неожиданные результаты, когда он запрашивает древовидную процедуру навигации. Я проследил, что проблема заключается в том, что встроенная процедура идентифицирует нулевые объекты в итерационных cte.

Код для тиражирования:

DROP TABLE IF EXISTS dbo.TestTable1;
DROP PROC IF EXISTS dbo.TestTableProc1;
DROP PROC IF EXISTS dbo.TestTableProc2;

CREATE TABLE dbo.TestTable1 (ParentID INT              NOT NULL
,                            ChildID  INT              NOT NULL
,                            Guid     UNIQUEIDENTIFIER NOT NULL);
GO

CREATE PROC dbo.TestTableProc1 (@Value1 INT)
AS
    BEGIN;
        WITH cte AS
            (SELECT T1.ParentID
             ,      T1.ChildID
             ,      T1.Guid
               FROM dbo.TestTable1 T1
              WHERE T1.ParentID = @Value1
             UNION ALL
             SELECT T1.ParentID
             ,      T1.ChildID
             ,      T1.Guid
               FROM dbo.TestTable1 T1)
        SELECT  cte.ParentID
        ,       cte.ChildID
        ,       cte.Guid
          FROM  cte;
    END;
GO

CREATE PROC dbo.TestTableProc2 (@Value1 INT)
AS
    BEGIN;
        WITH cte AS
            (SELECT T1.ParentID
             ,      T1.ChildID
             ,      T1.Guid
               FROM dbo.TestTable1 T1
              WHERE T1.ParentID = @Value1
             UNION ALL
             SELECT cte.ParentID
             ,      cte.ChildID
             ,      cte.Guid
               FROM dbo.TestTable1 T1
               JOIN cte ON T1.ParentID = cte.ChildID)
        SELECT  cte.ParentID
        ,       cte.ChildID
        ,       cte.Guid
          FROM  cte;
    END;
GO

SELECT  'dbo.TestTableProc1'
,       name
,       is_nullable
  FROM  sys.dm_exec_describe_first_result_set_for_object(OBJECT_ID('dbo.TestTableProc1'), 0)
UNION ALL
SELECT  'dbo.TestTableProc2'
,       name
,       is_nullable
  FROM  sys.dm_exec_describe_first_result_set_for_object(OBJECT_ID('dbo.TestTableProc2'), 0);

DROP PROC IF EXISTS dbo.TestTableProc1;
DROP PROC IF EXISTS dbo.TestTableProc2;
DROP TABLE IF EXISTS dbo.TestTable1;

Это дает набор результатов:

enter image description here

Как видно из результатов TestTableProc1 правильно идентифицирует все поля как ненулевые. Где, как TestTableProc2 идентифицирует все поля как обнуляемые, которыми они никогда не будут.

В качестве решения этой проблемы я могу переместить весь процесс в подпроцедуру, а затем вызвать подпрограмму с текущим именем и добавить предложение WITH RESULTSET, чтобы заблокировать вывод. Хотя это функциональный обходной путь, это означало бы снижение производительности и добавление дополнительных процедур в базу данных, где они не требуются.

Мне нужен способ получить правильное описание набора результатов, так как это редкий вызов, и я могу немного снизить производительность, вместо того, чтобы изменять саму основную процедуру.

Любые варианты с благодарностью получены.

...