Apakah RANK () dan DENSE_RANK () deterministik atau non-deterministik?


27

Menurut Microsoft BOL DENSE_RANK resmi adalah nondeterministic ( RANK () ). Tetapi menurut Fungsi Pemeringkatan oleh Itzik Ben-Gan "... fungsi RANK () dan DENSE_RANK () selalu bersifat deterministik". Siapa yang benar?

Apa yang saya temukan sejauh ini: Definisi Microsoft "Fungsi deterministik selalu mengembalikan hasil yang sama setiap kali mereka dipanggil dengan serangkaian nilai input tertentu dan diberi status database yang sama."

Jadi dalam tabel teori Set Karyawan

Employee            Salary
Sue Right            1.00
Robin Page           1.00
Phil Factor          1.00

dan Karyawan2

Employee            Salary
Phil Factor          1.00
Sue Right            1.00
Robin Page           1.00

adalah sama. Tetapi fungsi Pemeringkatan mengembalikan nilai yang berbeda:

    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

Jawaban:


23

Menurut Microsoft BOL DENSE_RANK resmi adalah nondeterministic (RANK ()). Tetapi menurut Fungsi Pemeringkatan oleh Itzik Ben-Gan "... fungsi RANK () dan DENSE_RANK () selalu bersifat deterministik". Siapa yang benar?

Keduanya benar, karena mereka menggunakan indera berbeda dari kata "deterministik".

Dari sudut pandang pengoptimal SQL Server, "deterministik" memiliki makna yang sangat tepat; makna yang ada sebelum fungsi jendela dan peringkat ditambahkan ke produk. Untuk pengoptimal, properti "deterministik" menentukan apakah suatu fungsi dapat secara bebas diduplikasi dalam struktur pohon internal selama optimasi. Ini tidak sah untuk fungsi non-deterministik.

Deterministik di sini berarti: instance yang tepat dari fungsi selalu mengembalikan output yang sama untuk input yang sama, tidak peduli berapa kali itu disebut. Ini tidak pernah benar untuk fungsi windowing, menurut definisi, karena sebagai fungsi skalar (baris tunggal), mereka tidak mengembalikan hasil yang sama di dalam baris atau melintasi baris. Untuk menyatakannya secara sederhana, gunakan ROW_NUMBERsebagai contoh:

The ROW_NUMBERmengembalikan fungsi nilai yang berbeda untuk baris yang berbeda (dengan definisi!), Jadi untuk tujuan optimasi itu nondeterministic

Ini adalah arti yang digunakan BOL.

Itzik membuat poin berbeda tentang determinisme hasil secara keseluruhan. Atas set input yang dipesan (dengan tie-breaking yang sesuai) outputnya adalah urutan "deterministik". Itu adalah pengamatan yang valid, tetapi bukan kualitas "deterministik" yang penting selama optimasi kueri.


10

NTILE()merupakan kasus yang menarik; tampaknya berlaku setelah pengurutan (yang, dalam kasus seri, diserahkan ke perangkat SQL Server sendiri, dan ini biasanya didorong oleh pilihan indeks yang paling efisien untuk keperluan pengurutan). Anda dapat membuat deterministik ini dengan tidak memaksa SQL Server untuk membuat pilihan sewenang-wenang di sini - tambahkan satu atau lebih tie-breaker ke OVER()klausa:

OVER (ORDER BY Salary, Employee)

Pada dasarnya Anda perlu membuat penyortiran menjadi unik. Jika Anda memiliki karyawan dengan nama yang sama, Anda mungkin harus memilih kolom tie-breaker yang berbeda atau terus menambahkan kolom sampai benar-benar tidak ada ikatan.

Untuk RANK()dan DENSE_RANK(), ikatan sebenarnya adalah alasan penting bahwa Anda tidak bisa mendapatkan nilai yang berbeda. Cobalah untuk tidak mengacaukan determinisme dari output fungsi dengan determinisme dari urutan hasil. Jika pertanyaan Anda tidak ada ORDER BY, lalu apa yang tidak deterministik tentang ini?

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()dan DENSE_RANK()menerapkan nilai yang sama dalam kedua kasus, SQL Server baru saja mengembalikan hasilnya kepada Anda dalam urutan yang berbeda. Ini tidak ada hubungannya dengan mengharapkan output yang sama dari RANK()atau DENSE_RANK()memberikan input yang sama - ini hanya tentang mengasumsikan atau mengharapkan beberapa urutan deterministik ketika Anda memberi tahu SQL Server (dengan menghilangkan ORDER BYklausa) bahwa Anda tidak peduli tentang urutan hasil. Lihat # 3 di sini:


7

Sintaksis:

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

Kedua fungsi, RANK()dan DENSE_RANK(), menurut definisi mereka, dijamin untuk menghasilkan hasil yang sama selama ekspresi dalam OVERklausa itu sendiri yang menentukan. Dan itulah yang dimaksud Itzik Ben-Gun dalam artikelnya. Daftar ini paling sering hanya kolom dari tabel yang terlibat.

Jadi, meskipun fungsinya umum tidak deterministik, implementasinya dapat dengan hati-hati membedakan kedua kasus dan menganggapnya deterministik atau tidak, setelah memeriksa partisi dan daftar pesanan.

Dugaan liar saya, adalah bahwa pengembang SQL-Server memutuskan lebih mudah untuk mengimplementasikannya seperti biasa "non-deterministik" meskipun hal ini bertentangan dengan cara definisi fungsi deterministik mereka. Jadi, mereka dinyatakan sebagai non-deterministik dalam MSDN karena dalam implementasi saat ini, mesin menganggap mereka selalu sebagai non-deterministik.

Satu argumen lagi adalah bahwa dua fungsi jendela lainnya, ROW_NUMBER()dan NTILE(), bahkan lebih rumit karena bagi mereka memiliki output yang identik, ekspresi dalam partisi dan urutan daftar tidak hanya harus deterministik tetapi unik juga. Jadi, mengimplementasikan semua detail itu jauh dari mudah.


Saya tidak akan mengomentari urutan set hasil, karena ini tidak ada hubungannya dengan determinisme, seperti yang Aaron Bertrand jelaskan dalam jawabannya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.