Ошибка в @@ROWCOUNT внутри SQL Server 2019 UDF

Я обнаружил, что @@ROWCOUNT, когда он используется внутри User Defined Function в MS SQL Server 2019, больше не работает должным образом.

Я не знаю, является ли это ошибкой MS SQL или желаемым изменением поведения.

Есть ли возможность вернуться к поведению 2019 года в предыдущих версиях? Это что-то о настройке установки?

Вот код и результаты для вашего собственного теста:

CREATE FUNCTION [dbo].[udfScalar](@test NVARCHAR(255)) RETURNS int
AS BEGIN
    DECLARE @var AS NVARCHAR(255)
    DECLARE @ROWCOUNT AS INT = NULL
    select top 1 @var = 'test' from FooTable where 1 = 0
    SET @ROWCOUNT = @@ROWCOUNT
    RETURN @ROWCOUNT;
END
GO
    DECLARE @var AS NVARCHAR(255)
    DECLARE @ROWCOUNT AS INT = NULL
    select top 1 @var = 'test' from FooTable where 1 = 0
    SET @ROWCOUNT = @@ROWCOUNT

select @ROWCOUNT '@@ROWCOUNT in T-SQL', [dbo].[udfScalar]('test') '@@ROWCOUNT in UDF', @@VERSION 'MS SQL VERSION'
drop FUNCTION [dbo].[udfScalar]

Результат в MS SQL Server 2019 (неправильный):

@@ROWCOUNT in T-SQL: 0
@@ROWCOUNT in UDF:   1
MS SQL VERSION: Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64) 
    Sep 24 2019 13:48:23 
    Copyright (C) 2019 Microsoft Corporation
    Standard Edition (64-bit) on Windows Server 2019 Standard 10.0 <X64> (Build 17763: ) (Hypervisor)

Обратите внимание, что UDF возвращает 1, когда результат должен быть 0 из-за where 1 = 0.

Результат в MS SQL Server 2016 и предыдущих версиях (правильно):

@@ROWCOUNT in T-SQL: 0
@@ROWCOUNT in UDF:   0
MS SQL VERSION: Microsoft SQL Server 2016 (SP2-GDR) (KB4505220) - 13.0.5101.9 (X64) 
    Jun 15 2019 23:15:58 
    Copyright (c) Microsoft Corporation
    Standard Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64> (Build 14393: ) (Hypervisor)

Сейчас у меня нет доступа к SQL Server 2017, но я считаю, что это было правильно.


person Alex    schedule 12.02.2020    source источник
comment
Я подозреваю, что это случай скалярного встраивания. Если вы используете WITH INLINE = OFF (см. Отключение встраивания скалярных UDF без изменения уровня совместимости) в объявлении функции вы получаете правильные результаты ? В идеале следует избегать пользовательских скалярных функций, поскольку известно, что они плохо работают.   -  person Larnu    schedule 12.02.2020
comment
Хотя это кажется не вопросом. Зачем вам нужно подсчитывать количество строк, где 1 = 0 и зачем использовать @@ROWCOUNT, когда у вас есть отличная функция COUNT для достижения этой цели. Это сценарий, который никогда не существовал бы в реальном мире, так почему же поведение имеет значение?   -  person Larnu    schedule 12.02.2020
comment
@Larnu 1=0 - глупый пример, демонстрирующий, что @@ROWCOUNT = 1 это не ожидаемое значение.   -  person Alex    schedule 12.02.2020
comment
Но почему бы просто не использовать COUNT?   -  person Larnu    schedule 12.02.2020


Ответы (2)


Это известная ошибка, связанная с встраиванием UDF. Встраивание определяемых пользователем функций было добавлено в SQL Server 2019 для повышения производительности определяемых пользователем функций. Вам необходимо установить последнюю версию CU, начиная с SQL Server 2019 CU2. Если UDF содержит @@ROWCOUNT, UDF больше не будет встроен. В противном случае вы можете добавить опцию WITH INLINE = OFF.

Чтобы получить больше информации:

person Luca Biondi    schedule 15.05.2020

Ответ @Larnu правильный, это изменение поведения связано со скалярным встраиванием.

Добавление модификатора WITH INLINE = OFF работает как положено.

CREATE FUNCTION [dbo].[udfScalar](@test NVARCHAR(255)) RETURNS int
WITH INLINE = OFF
AS BEGIN
    DECLARE @var AS NVARCHAR(255)
    DECLARE @ROWCOUNT AS INT = NULL
    select top 1 @var = 'test' from FooTable where 1 = 0
    SET @ROWCOUNT = @@ROWCOUNT
    RETURN @ROWCOUNT;
END
person Alex    schedule 12.02.2020