Чи детерміновані чи недетерміновані RANK () та DENSE_RANK ()?


27

На думку офіційного Microsoft BOL, DENSE_RANK є недетермінованим ( RANK () ). Але відповідно до функцій ранжирування Ітзіка Бен-Гана, "... функції RANK () і DENSE_RANK () завжди детерміновані". Хто правий?

Що я знайшов поки що: Визначення Майкрософт "Детерміновані функції завжди повертають один і той же результат кожного разу, коли вони викликаються певним набором вхідних значень і даються однаковий стан бази даних".

Так у таблицях теорії задають працівники

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.

Іцик робить інший пункт щодо детермінованості результату в цілому. Над впорядкованим набором входів (з відповідним розривом зв'язку) вихід є "детермінованою" послідовністю. Це справедливе спостереження, але не "детермінована" якість важлива під час оптимізації запитів.


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-Server вирішили, що їх легше реалізувати як завжди "недетерміновані", незважаючи на те, що це певним чином суперечить їх визначенню детермінованих функцій. Отже, вони вказані як недетерміновані в MSDN, оскільки в поточній реалізації механізм розглядає їх завжди як недетерміновані.

Ще один аргумент полягає в тому, що інші два функції вікна, ROW_NUMBER()і NTILE(), є ще складнішими, оскільки для них, що мають однаковий вихід, вираз у розділі та порядку за списками має бути не лише детермінованим, але й унікальним. Отже, реалізація всіх цих деталей далеко не банальна.


Я не буду коментувати порядок результативних наборів, оскільки це не має нічого спільного з детермінізмом, як чітко пояснив Аарон Бертран у своїй відповіді.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.