Mengapa aliran agregat ini diperlukan?

12

Lihat kueri ini. Ini cukup sederhana (lihat akhir posting untuk definisi tabel dan indeks, dan skrip repro):

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);

Catatan: "AND 1 = (PILIH 1) hanya untuk menjaga agar kueri ini tidak diparameterisasi secara otomatis, yang menurut saya membingungkan masalah - itu sebenarnya mendapatkan paket yang sama dengan atau tanpa klausa itu sekalipun

Dan inilah rencananya ( rekatkan tautan paket) :

rencanakan dengan aliran arus

Karena ada "top 1" di sana, saya terkejut melihat operator agregat aliran. Sepertinya tidak perlu bagi saya, karena dijamin hanya ada satu baris.

Untuk menguji teori itu, saya mencoba kueri yang setara secara logis ini:

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;

Inilah paket untuk yang itu ( rekatkan tautan paket ):

rencana tanpa ags aliran

Benar saja, grup berdasarkan rencana dapat bertahan tanpa operator agregat aliran.

Perhatikan bahwa kedua kueri membaca "mundur" dari akhir indeks dan lakukan "top 1" untuk mendapatkan revisi maksimal.

Apa yang kulewatkan di sini? Apakah agregat aliran benar-benar berfungsi di kueri pertama, atau haruskah itu dapat dihilangkan (dan itu hanya batasan pengoptimal yang bukan)?

Ngomong-ngomong, saya menyadari ini bukan masalah yang sangat praktis (kedua pertanyaan melaporkan 0 ms dari CPU dan waktu berlalu), saya hanya ingin tahu tentang internal / perilaku yang dipamerkan di sini.


Berikut kode pengaturan yang saya jalankan sebelum menjalankan dua pertanyaan di atas:

DROP TABLE IF EXISTS dbo.TheOneders;
GO

CREATE TABLE dbo.TheOneders
(
    Id INT NOT NULL,
    Revision SMALLINT NOT NULL,
    Something NVARCHAR(23),

    CONSTRAINT PK_TheOneders PRIMARY KEY NONCLUSTERED (Id, Revision)
);
GO

INSERT INTO dbo.TheOneders
    (Id, Revision, Something)
SELECT DISTINCT TOP 1000 
    1, m.message_id, 'Do...'
FROM sys.messages m
ORDER BY m.message_id
OPTION (MAXDOP 1);

INSERT INTO dbo.TheOneders
    (Id, Revision, Something)
SELECT DISTINCT TOP 100 
    2, m.message_id, 'Do that thing you do...'
FROM sys.messages m
ORDER BY m.message_id
OPTION (MAXDOP 1);
GO
Josh Darnell
sumber

Jawaban:

16

Anda dapat melihat peran agregat ini jika tidak ada baris yang cocok dengan WHEREklausa.

SELECT MAX(Revision)
FROM   dbo.TheOneders
WHERE  Id = 1
       AND 1 = 1 /*To avoid auto parameterisation*/
       AND Id%3 = 4  /*always false*/

Dalam hal ini, nol baris masuk ke agregat tetapi masih memancarkan satu sebagai semantik yang benar untuk kembali NULLdalam kasus ini.

masukkan deskripsi gambar di sini

Ini adalah agregat skalar yang bertentangan dengan yang vektor.

Kueri "setara secara logis" Anda tidak setara. Menambahkan GROUP BY Idakan menjadikannya agregat vektor dan kemudian perilaku yang benar adalah tidak mengembalikan baris.

Lihat Bersenang-senang dengan Agregat Skal dan Vektor untuk informasi lebih lanjut tentang ini.

Martin Smith
sumber