Являются ли RANK () и DENSE_RANK () детерминированными или недетерминированными?

27

Согласно официальному сообщению Microsoft, BOL DENSE_RANK является недетерминированным ( RANK () ). Но согласно функциям ранжирования Ицик Бен-Гана «... функции RANK () и DENSE_RANK () всегда детерминированы». Кто прав?

То, что я нашел до сих пор: определение Microsoft «Детерминированные функции всегда возвращают один и тот же результат каждый раз, когда они вызываются с определенным набором входных значений и при том же состоянии базы данных».

Так в таблицах теории множеств Сотрудники

Employee            Salary
Sue Right            1.00
Robin Page           1.00
Phil Factor          1.00

и сотрудники2

Employee            Salary
Phil Factor          1.00
Sue Right            1.00
Robin Page           1.00

такие же. Но функции ранжирования возвращают разные значения:

    CREATE TABLE [dbo].[Employees](
    --[ID] [int] IDENTITY(1,1) NOT NULL,
    [Employee] [varchar](150) NOT NULL,
    [Salary] [smallmoney] NULL,
) ON [PRIMARY]

GO
CREATE TABLE [dbo].[Employees2](
    --[ID] [int] IDENTITY(1,1) NOT NULL,
    [Employee] [varchar](150) NOT NULL,
    [Salary] [smallmoney] NULL,
) ON [PRIMARY]

INSERT INTO [dbo].[Employees]
([Employee] ,[Salary])
VALUES
('Sue Right', 1)
, ('Robin Page', 1)
,('Phil Factor', 1 )
GO
INSERT INTO [dbo].[Employees2]
([Employee] ,[Salary])
VALUES
('Phil Factor', 1 )
,('Sue Right', 1)
,('Robin Page', 1)
GO
SELECT RANK() OVER ( ORDER BY Salary) AS [Rank]
, DENSE_RANK() OVER (ORDER BY Salary ) AS [Dense_rank]
, [Employee]
FROM
dbo.Employees

SELECT RANK() OVER ( ORDER BY Salary) AS [Rank]
, DENSE_RANK() OVER (ORDER BY Salary ) AS [Dense_rank]
, [Employee]
FROM
dbo.Employees2

SELECT NTILE(3) OVER ( ORDER BY SALARY )
, [Employee]
FROM
dbo.Employees

SELECT NTILE(3) OVER ( ORDER BY SALARY )
, [Employee]
FROM
dbo.Employees2
Павел Нефёдов
источник

Ответы:

23

Согласно официальному сообщению Microsoft, BOL DENSE_RANK является недетерминированным (RANK ()). Но согласно функциям ранжирования Ицик Бен-Гана «... функции RANK () и DENSE_RANK () всегда детерминированы». Кто прав?

Они оба правы, потому что они используют разные значения слова «детерминистический».

С точки зрения оптимизатора SQL Server, «детерминированный» имеет очень точное значение; значение, существовавшее до того, как функции окна и ранжирования были добавлены в продукт. Для оптимизатора свойство «детерминистическое» определяет, может ли функция быть свободно продублирована во внутренних структурах дерева во время оптимизации. Это недопустимо для недетерминированной функции.

Детерминированный здесь означает: точный экземпляр функции всегда возвращает один и тот же вывод для одного и того же ввода, независимо от того, сколько раз он вызывается. Это никогда не верно для оконных функций, по определению, потому что как скалярная функция (одна строка), они не возвращают один и тот же результат в строке или между строками. Чтобы сформулировать это просто, используя ROW_NUMBERв качестве примера:

ROW_NUMBERФункция возвращает разные значения для разных строк (по определению!), Поэтому для целей оптимизации является недетерминировано

В этом смысл BOL.

Ицик высказывает другое мнение о детерминизме результата в целом. Над упорядоченным входным набором (с подходящим разрывом связей) выход является «детерминированной» последовательностью. Это правильное наблюдение, но это не «детерминированное» качество, которое важно при оптимизации запросов.

Пол Уайт говорит, что GoFundMonica
источник
10

NTILE()интересный случай; похоже, он применяется после сортировки (которая в случае привязки оставляется на собственные устройства SQL Server, и это обычно обусловлено наиболее эффективным выбором индекса для целей сортировки). Вы можете сделать это детерминированным, не заставляя SQL Server делать здесь произвольный выбор - добавьте один или несколько прерывателей связей кOVER() предложение:

OVER (ORDER BY Salary, Employee)

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

Для RANK()и DENSE_RANK(), на самом деле, связи являются решающей причиной того, что вы не можете получить разные значения. Постарайтесь не путать детерминизм вывода функции с детерминизмом порядка результатов. Если ваши запросы не имеют ORDER BY, то что не является детерминированным по этому поводу?

1   1   Sue Right
1   1   Robin Page
1   1   Phil Factor

1   1   Phil Factor
1   1   Sue Right
1   1   Robin Page

RANK()и DENSE_RANK()применяя одинаковые значения в обоих случаях, SQL Server просто возвращал вам результаты в другом порядке. Это не имеет ничего общего с ожиданием одного и того же вывода RANK()или DENSE_RANK()с одним и тем же вводом - это просто принятие или ожидание некоторого детерминированного порядка, когда вы сказали SQL Server (пропуская ORDER BYпредложение), что вас не волнует порядок результаты. Смотрите № 3 здесь:

Аарон Бертран
источник
7

Синтаксис:

WindowFunction() OVER (PARTITION BY <some expressions>        -- partition list
                       ORDER BY <some other expressions>)     -- order list

Обе функции RANK()и DENSE_RANK(), по их определениям, гарантированно дают одинаковые результаты, если выражения в OVERпредложении сами по себе являются детерминированными. И это то, что Ицик Бен-Гун имел в виду в своей статье. Эти списки чаще всего являются просто столбцами соответствующих таблиц.

Таким образом, хотя функции общего характера не являются детерминированными, при их реализации можно было бы позаботиться о том, чтобы различать два случая и считать их детерминированными или нет, при рассмотрении списков разделов и порядков.

Я предпочитаю предположить, что разработчики SQL-сервера решили, что проще реализовать их как всегда «недетерминированные», несмотря на то, что это каким-то образом противоречит их определению детерминированных функций. Таким образом, они определены как недетерминированные в MSDN, потому что в текущей реализации механизм всегда рассматривает их как недетерминированные.

Еще один аргумент заключается в том, что две другие оконные функции, ROW_NUMBER()и NTILE(), еще более сложны, потому что для них, имеющих одинаковый вывод, выражение в разделе и порядок по спискам должны быть не только детерминированными, но и уникальными. Таким образом, реализация всех этих деталей далеко не тривиальна.


Я не буду комментировать порядок наборов результатов, так как это не имеет никакого отношения к детерминизму, как четко объяснил Аарон Бертран в своем ответе.

ypercubeᵀᴹ
источник