Faktor biaya manakah yang masuk ke pengoptimal memilih berbagai jenis gulungan?

15

Spoolum

Di SQL Server ada beberapa jenis gulungan. Dua yang saya tertarik adalah Spool Tabel dan Indeks spool , di luar permintaan modifikasi .

Hanya baca kueri, khususnya di sisi bagian dalam gabungan Nested Loops, dapat menggunakan spool Tabel atau Indeks untuk berpotensi mengurangi I / O dan meningkatkan kinerja kueri. Gulungan ini bisa Eager atau Malas . Sama seperti Anda dan saya.

Pertanyaan saya adalah:

  • Faktor mana yang masuk ke dalam pilihan Spool Tabel vs.
  • Faktor mana yang menjadi pilihan antara Eager dan Lazy Spools
Erik Darling
sumber

Jawaban:

12

Ini agak luas tapi saya pikir saya mengerti Pertanyaan Sejati dan akan menjawabnya. Hanya akan berbicara tentang tabel vs indeks spool. Saya tidak berpikir itu benar untuk melihat di sana sebagai pilihan antara tabel dan spool indeks. Seperti yang Anda ketahui, dimungkinkan dalam subtree tunggal untuk mendapatkan spool indeks, spool tabel, atau keduanya spool indeks dan spool tabel. Saya percaya secara umum benar untuk mengatakan bahwa Anda mendapatkan spool indeks dalam kondisi berikut:

  1. Pengoptimal kueri memiliki alasan untuk mengubah suatu sambungan menjadi suatu penerapan
  2. Pengoptimal kueri benar-benar melakukan transformasi untuk menerapkan
  3. Pengoptimal kueri menggunakan aturan untuk menambahkan spool indeks (minimal spool indeks harus aman untuk digunakan)
  4. Paket dengan spool indeks dipilih

Anda dapat melihat sebagian besar dari ini dengan demo sederhana. Mulailah dengan membuat sepasang tumpukan:

DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;


DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);

INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Untuk kueri pertama, tidak ada yang dicari:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);

Jadi tidak ada alasan bagi pengoptimal untuk mengubah bergabung menjadi berlaku. Anda berakhir dengan gulungan meja karena alasan penetapan biaya. Jadi kueri ini gagal pada tes pertama.

masukkan deskripsi gambar di sini

Untuk kueri berikutnya, wajar berharap bahwa pengoptimal memiliki alasan untuk mempertimbangkan penerapan:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID 
OPTION (LOOP JOIN, MAXDOP 1);

Tapi itu tidak dimaksudkan sebagai:

masukkan deskripsi gambar di sini

Permintaan ini gagal pada pengujian kedua. Penjelasan lengkap ada di sini . Mengutip bagian yang paling relevan:

Pengoptimal tidak mempertimbangkan membangun indeks dengan cepat untuk memungkinkan penerapan; alih-alih urutan kejadian biasanya adalah kebalikannya: transformasi untuk diterapkan karena indeks yang baik ada.

Saya dapat menulis ulang kueri untuk mendorong pengoptimal mempertimbangkan penerapan:

SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);

Tapi masih belum ada spool indeks:

masukkan deskripsi gambar di sini

Kueri ini gagal pada pengujian ketiga. Di SQL Server 2014 ada batas panjang kunci indeks 900 byte. Ini diperluas di SQL Server 2016 tetapi hanya untuk indeks yang tidak dibatasi. Indeks untuk spool adalah indeks berkerumun sehingga batasnya tetap pada 900 byte . Dalam kasus apa pun, aturan spool indeks tidak dapat diterapkan karena dapat menyebabkan kesalahan selama eksekusi permintaan.

Mengurangi panjang tipe data menjadi 800 akhirnya menyediakan paket dengan spool indeks:

masukkan deskripsi gambar di sini

Rencana spool indeks, tidak mengherankan, dihitung biayanya secara signifikan lebih murah daripada rencana tanpa spool: 89.7603 unit vs 598.832 unit. Anda dapat melihat perbedaannya dengan QUERYRULEOFF BuildSpoolpetunjuk permintaan tidak berdokumen :

masukkan deskripsi gambar di sini

Ini bukan jawaban yang lengkap, tapi mudah-mudahan ini adalah sebagian dari apa yang Anda cari.

Joe Obbish
sumber