Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Masalah Halloween – Bagian 4

[ Bagian 1 | Bagian 2 | Bagian 3 | Bagian 4 ]

Masalah Halloween dapat memiliki sejumlah efek penting pada rencana eksekusi. Di bagian akhir seri ini, kita melihat trik yang dapat diterapkan oleh pengoptimal untuk menghindari Masalah Halloween saat menyusun rencana untuk kueri yang menambah, mengubah, atau menghapus data.

Latar Belakang

Selama bertahun-tahun, sejumlah pendekatan telah dicoba untuk menghindari Masalah Halloween. Salah satu teknik awal adalah menghindari pembuatan rencana eksekusi apa pun yang melibatkan membaca dari dan menulis ke kunci dari indeks yang sama. Ini tidak terlalu berhasil dari sudut pandang kinerja, paling tidak karena sering kali berarti memindai tabel dasar daripada menggunakan indeks nonclustered selektif untuk menemukan baris yang akan diubah.

Pendekatan kedua adalah memisahkan sepenuhnya fase membaca dan menulis kueri pembaruan, dengan terlebih dahulu menempatkan semua baris yang memenuhi syarat untuk perubahan, menyimpannya di suatu tempat, dan baru kemudian mulai melakukan perubahan. Di SQL Server, pemisahan fase penuh dicapai dengan menempatkan Eager Table Spool yang sekarang dikenal di sisi input operator pembaruan:

Spool membaca semua baris dari inputnya dan menyimpannya di tempdb . yang tersembunyi meja kerja. Halaman tabel kerja ini mungkin tetap berada di memori, atau mungkin memerlukan ruang disk fisik jika kumpulan barisnya besar, atau jika server berada di bawah tekanan memori.

Pemisahan fase penuh bisa jadi kurang ideal karena kami umumnya ingin menjalankan rencana sebanyak mungkin sebagai saluran pipa, di mana setiap baris diproses sepenuhnya sebelum pindah ke yang berikutnya. Pipelining memiliki banyak keuntungan termasuk menghindari kebutuhan akan penyimpanan sementara, dan hanya menyentuh setiap baris satu kali.

Pengoptimal SQL Server

SQL Server melangkah lebih jauh dari dua teknik yang dijelaskan sejauh ini, meskipun tentu saja menyertakan keduanya sebagai opsi. Pengoptimal kueri SQL Server mendeteksi kueri yang memerlukan Perlindungan Halloween, menentukan berapa banyak perlindungan diperlukan, dan menggunakan berbasis biaya analisis untuk menemukan metode termurah untuk memberikan perlindungan tersebut.

Cara termudah untuk memahami aspek Masalah Halloween ini adalah dengan melihat beberapa contoh. Di bagian berikut, tugasnya adalah menambahkan rentang angka ke tabel yang ada – tetapi hanya angka yang belum ada:

CREATE TABLE dbo.Test( pk integer NOT NULL, CONSTRAINT PK_Test PRIMARY KEY CLUSTERED (pk));

5 baris

Contoh pertama memproses rentang angka dari 1 hingga 5 inklusif:

INSERT dbo.Test (pk)SELECT Num.n FROM dbo.Numbers AS NumWHERE Num.n ANTARA 1 DAN 5 DAN TIDAK ADA ( SELECT NULL FROM dbo.Test AS t WHERE t.pk =Num.n ); 

Karena kueri ini membaca dari dan menulis ke kunci dari indeks yang sama pada tabel Uji, rencana eksekusi memerlukan Perlindungan Halloween. Dalam hal ini, pengoptimal menggunakan pemisahan fase penuh menggunakan Eager Table Spool:

50 baris

Dengan lima baris sekarang di tabel Uji, kami menjalankan kueri yang sama lagi, mengubah WHERE klausa untuk memproses angka dari 1 hingga 50 inklusif :

Paket ini memberikan perlindungan yang tepat terhadap Masalah Halloween, tetapi tidak menampilkan Eager Table Spool. Pengoptimal mengenali bahwa operator gabungan Hash Match memblokir input build-nya; semua baris dibaca ke dalam tabel hash sebelum operator memulai proses pencocokan menggunakan baris dari input probe. Akibatnya, rencana ini secara alami menyediakan pemisahan fase (hanya untuk tabel Uji) tanpa memerlukan spool.

Pengoptimal memilih paket bergabung dengan Hash Match daripada bergabung dengan Nested Loops yang terlihat dalam paket 5 baris karena alasan berbasis biaya. Paket Hash Match 50 baris memiliki perkiraan biaya total 0,0347345 unit. Kami dapat memaksa paket Nested Loops yang digunakan sebelumnya dengan petunjuk untuk melihat mengapa pengoptimal tidak memilih nested loops:

Paket ini memiliki perkiraan biaya 0,0379063 unit termasuk spool, sedikit lebih banyak dari rencana Hash Match.

500 Baris

Dengan 50 baris sekarang di tabel Uji, kami semakin meningkatkan kisaran angka menjadi 500 :

Kali ini, pengoptimal memilih Merge Join, dan sekali lagi tidak ada Eager Table Spool. Operator Sortir menyediakan pemisahan fase yang diperlukan dalam rencana ini. Ini sepenuhnya menggunakan inputnya sebelum mengembalikan baris pertama (pengurutan tidak dapat mengetahui baris mana yang diurutkan terlebih dahulu sampai semua baris terlihat). Pengoptimal memutuskan bahwa menyortir 50 baris dari tabel Uji akan lebih murah daripada spooling bersemangat 450 baris tepat sebelum operator pembaruan.

Paket Sortir plus Gabung Gabung memiliki perkiraan biaya 0.0362708 unit. Alternatif rencana Hash Match dan Nested Loops keluar pada 0.0385677 unit dan 0.112433 unit masing-masing.

Ada yang aneh dengan Sortir

Jika Anda telah menjalankan contoh-contoh ini untuk diri Anda sendiri, Anda mungkin telah memperhatikan sesuatu yang aneh tentang contoh terakhir itu, terutama jika Anda melihat tips alat Plan Explorer untuk tabel Uji Cari dan Sortir:

Seek menghasilkan memerintahkan aliran pk nilai, jadi apa gunanya menyortir pada kolom yang sama segera sesudahnya? Untuk menjawab pertanyaan (sangat masuk akal) itu, kita mulai dengan hanya melihat SELECT bagian dari INSERT permintaan:

SELECT Num.n FROM dbo.Numbers AS NumWHERE Num.n ANTARA 1 DAN 500 DAN TIDAK ADA ( PILIH 1 FROM dbo.Test AS t WHERE t.pk =Num.n )ORDER BY Num.n;

Kueri ini menghasilkan rencana eksekusi di bawah ini (dengan atau tanpa ORDER BY Saya menambahkan untuk mengatasi keberatan teknis tertentu yang mungkin Anda miliki):

Perhatikan kurangnya operator Sortir. Jadi mengapa INSERT rencana termasuk Sortir? Hanya untuk menghindari Masalah Halloween. Pengoptimal menganggap bahwa melakukan pengurutan berlebihan (dengan pemisahan fase bawaannya) adalah cara termurah untuk mengeksekusi kueri dan menjamin hasil yang benar. Pintar.

Tingkat dan Properti Perlindungan Halloween

Pengoptimal SQL Server memiliki fitur khusus yang memungkinkannya mempertimbangkan tingkat Perlindungan Halloween (HP) yang diperlukan pada setiap titik dalam rencana kueri, dan efek terperinci yang dimiliki setiap operator. Fitur tambahan ini digabungkan ke dalam kerangka properti yang sama yang digunakan pengoptimal untuk melacak ratusan bit informasi penting lainnya selama aktivitas pencariannya.

Setiap operator memiliki wajib Properti HP dan terkirim properti HP. wajib properti menunjukkan tingkat HP yang dibutuhkan pada saat itu di pohon untuk hasil yang benar. terkirim properti mencerminkan HP yang disediakan oleh operator saat ini dan kumulatif Efek HP disediakan oleh subpohonnya.

Pengoptimal berisi logika untuk menentukan bagaimana setiap operator fisik (misalnya, Skalar Hitung) memengaruhi level HP. Dengan menjelajahi berbagai alternatif paket dan menolak paket di mana HP yang dikirimkan kurang dari HP yang dibutuhkan di operator pembaruan, pengoptimal memiliki cara yang fleksibel untuk menemukan paket yang benar dan efisien yang tidak selalu memerlukan Eager Table Spool.

Perubahan rencana untuk Perlindungan Halloween

Kami melihat pengoptimal menambahkan semacam berlebihan untuk Perlindungan Halloween dalam contoh Gabung Gabung sebelumnya. Bagaimana kita bisa yakin ini lebih efisien daripada Eager Table Spool sederhana? Dan bagaimana kami bisa mengetahui fitur mana dari paket pembaruan yang hanya tersedia untuk Perlindungan Halloween?

Kedua pertanyaan dapat dijawab (dalam lingkungan pengujian, tentu saja) menggunakan tanda jejak tidak berdokumen 8692 , yang memaksa pengoptimal untuk menggunakan Eager Table Spool untuk Perlindungan Halloween. Ingatlah bahwa rencana Gabung Gabung dengan jenis yang berlebihan memiliki perkiraan biaya 0.0362708 unit pengoptimal ajaib. Kita dapat membandingkannya dengan alternatif Eager Table Spool dengan mengkompilasi ulang kueri dengan trace flag 8692 diaktifkan:

INSERT dbo.Test (pk)SELECT Num.n FROM dbo.Numbers AS NumWHERE Num.n ANTARA 1 DAN 500 DAN TIDAK ADA ( PILIH 1 FROM dbo.Test AS t WHERE t.pk =Num.n )OPTION ( QUERYTRACEON 8692);

Paket Eager Spool memiliki perkiraan biaya 0.0378719 unit (naik dari 0.0362708 dengan jenis yang berlebihan). Perbedaan biaya yang ditampilkan di sini tidak terlalu signifikan karena sifat tugas yang sepele dan ukuran baris yang kecil. Kueri pembaruan dunia nyata dengan pohon kompleks dan jumlah baris yang lebih besar sering kali menghasilkan rencana yang jauh lebih efisien berkat kemampuan pengoptimal SQL Server untuk memikirkan secara mendalam tentang Perlindungan Halloween.

Opsi non-gulungan lainnya

Memposisikan operator pemblokiran secara optimal dalam rencana bukanlah satu-satunya strategi yang terbuka bagi pengoptimal untuk meminimalkan biaya memberikan perlindungan terhadap Masalah Halloween. Itu juga dapat memberi alasan tentang rentang nilai yang sedang diproses, seperti yang ditunjukkan oleh contoh berikut:

CREATE TABLE #Test( pk integer IDENTITY PRIMARY KEY, some_value integer); BUAT INDEKS i PADA #Test (some_value); -- Anggap tabel memiliki banyak data di dalamnya UPDATE STATISTICS #TestWITH ROWCOUNT =123456, PAGECOUNT =1234; UPDATE #TestSET some_value =10WHERE some_value =5;

Rencana eksekusi menunjukkan tidak perlunya Perlindungan Halloween, meskipun faktanya kami membaca dan memperbarui kunci indeks umum:

Pengoptimal dapat melihat bahwa mengubah 'some_value' dari 5 menjadi 10 tidak akan pernah menyebabkan baris yang diperbarui terlihat untuk kedua kalinya oleh Pencarian Indeks (yang hanya mencari baris di mana some_value adalah 5). Alasan ini hanya mungkin jika nilai literal digunakan dalam kueri, atau jika kueri menentukan OPTION (RECOMPILE) , memungkinkan pengoptimal untuk mengendus nilai parameter untuk rencana eksekusi satu kali.

Bahkan dengan nilai literal dalam kueri, pengoptimal dapat dicegah untuk menerapkan logika ini jika opsi database FORCED PARAMETERIZATION adalah ON . Dalam hal ini, nilai literal dalam kueri diganti dengan parameter, dan pengoptimal tidak dapat lagi memastikan bahwa Perlindungan Halloween tidak diperlukan (atau tidak akan diperlukan saat paket digunakan kembali dengan nilai parameter yang berbeda):

Jika Anda bertanya-tanya apa yang terjadi jika FORCED PARAMETERIZATION diaktifkan dan kueri menentukan OPTION (RECOMPILE) , jawabannya adalah pengoptimal mengkompilasi rencana untuk nilai yang diendus, sehingga dapat menerapkan pengoptimalan. Seperti biasa dengan OPTION (RECOMPILE) , paket kueri nilai spesifik tidak di-cache untuk digunakan kembali.

Atas

Contoh terakhir ini menunjukkan bagaimana Top operator dapat menghapus kebutuhan akan Perlindungan Halloween:

UPDATE TOP (1) tSET some_value +=1FROM #Test AS tWHERE some_value <=10;

Tidak diperlukan perlindungan karena kami hanya memperbarui satu baris. Nilai yang diperbarui tidak dapat ditemukan oleh Pencarian Indeks, karena pipa pemrosesan berhenti segera setelah baris pertama diperbarui. Sekali lagi, pengoptimalan ini hanya dapat diterapkan jika nilai literal konstan digunakan di TOP , atau jika variabel yang mengembalikan nilai '1' diendus menggunakan OPTION (RECOMPILE) .

Jika kita mengubah TOP (1) dalam kueri ke TOP (2) , pengoptimal memilih Clustered Index Scan daripada Index Seek:

Kami tidak memperbarui kunci indeks berkerumun, jadi paket ini tidak memerlukan Perlindungan Halloween. Memaksa penggunaan indeks nonclustered dengan petunjuk di TOP (2) query membuat biaya perlindungan menjadi jelas:

Pengoptimal memperkirakan Pemindaian Indeks Berkelompok akan lebih murah daripada paket ini (dengan Perlindungan Halloween ekstra).

Odds dan Ends

Ada beberapa poin lain yang ingin saya sampaikan tentang Perlindungan Halloween yang belum menemukan tempat alami dalam seri sebelumnya sekarang. Yang pertama adalah pertanyaan tentang Perlindungan Halloween saat level isolasi versi baris sedang digunakan.

Versi Baris

SQL Server menyediakan dua tingkat isolasi, READ COMMITTED SNAPSHOT dan SNAPSHOT ISOLATION yang menggunakan toko versi di tempdb untuk memberikan tampilan database yang konsisten pada tingkat pernyataan atau transaksi. SQL Server dapat menghindari Perlindungan Halloween sepenuhnya di bawah tingkat isolasi ini, karena penyimpanan versi dapat menyediakan data yang tidak terpengaruh oleh perubahan apa pun yang mungkin telah dibuat oleh pernyataan yang sedang dijalankan sejauh ini. Ide ini saat ini tidak diimplementasikan dalam versi SQL Server yang dirilis, meskipun Microsoft telah mengajukan paten yang menjelaskan bagaimana ini akan bekerja, jadi mungkin versi masa depan akan menggabungkan teknologi ini.

Heaps dan Rekaman yang Diteruskan

Jika Anda terbiasa dengan bagian dalam struktur heap, Anda mungkin bertanya-tanya apakah Masalah Halloween tertentu mungkin terjadi saat rekaman yang diteruskan dibuat dalam tabel heap. Jika ini baru bagi Anda, catatan tumpukan akan diteruskan jika baris yang ada diperbarui sehingga tidak lagi muat di halaman data asli. Mesin meninggalkan rintisan penerusan, dan memindahkan rekaman yang diperluas ke halaman lain.

Masalah dapat terjadi jika rencana yang berisi pemindaian tumpukan memperbarui catatan sedemikian rupa sehingga diteruskan. Pemindaian tumpukan mungkin menemukan baris lagi saat posisi pemindaian mencapai halaman dengan catatan yang diteruskan. Di SQL Server, masalah ini dihindari karena Mesin Penyimpanan menjamin untuk selalu segera mengikuti petunjuk penerusan. Jika pemindaian menemukan catatan yang telah diteruskan, itu akan mengabaikannya. Dengan perlindungan ini, pengoptimal kueri tidak perlu khawatir tentang skenario ini.

SCHEMABINDING dan Fungsi Skalar T-SQL

Ada sangat sedikit kesempatan ketika menggunakan fungsi skalar T-SQL adalah ide yang baik, tetapi jika Anda harus menggunakannya, Anda harus menyadari efek penting yang dapat ditimbulkannya terkait Perlindungan Halloween. Kecuali jika fungsi skalar dideklarasikan dengan SCHEMABINDING pilihan, SQL Server mengasumsikan fungsi mengakses tabel. Sebagai ilustrasi, perhatikan fungsi skalar T-SQL sederhana di bawah ini:

BUAT FUNGSI dbo.ReturnInput( @value integer)RETURNS integerASBEGIN RETURN @value;END;

Fungsi ini tidak mengakses tabel apa pun; sebenarnya itu tidak melakukan apa pun kecuali mengembalikan nilai parameter yang diteruskan ke sana. Sekarang lihat INSERT berikut ini permintaan:

DECLARE @T SEBAGAI TABEL (ProductID integer PRIMARY KEY); INSERT @T (ProductID)SELECT p.ProductIDFROM AdventureWorks2012.Production.Product AS p;

Rencana eksekusi persis seperti yang kami harapkan, tanpa perlu Perlindungan Halloween:

Namun, menambahkan fungsi tidak melakukan apa pun memiliki efek dramatis:

DECLARE @T SEBAGAI TABEL (ProductID integer PRIMARY KEY); INSERT @T (ProductID)SELECT dbo.ReturnInput(p.ProductID)FROM AdventureWorks2012.Production.Product AS p;

Rencana eksekusi sekarang termasuk Eager Table Spool untuk Halloween Protection. SQL Server mengasumsikan fungsi mengakses data, yang mungkin termasuk membaca dari tabel Produk lagi. Seperti yang Anda ingat, sebuah INSERT paket yang berisi referensi ke tabel target di sisi pembacaan paket memerlukan Perlindungan Halloween penuh, dan sejauh yang diketahui pengoptimal, hal itu mungkin terjadi di sini.

Menambahkan SCHEMABINDING opsi untuk definisi fungsi berarti SQL Server memeriksa isi fungsi untuk menentukan tabel mana yang diaksesnya. Itu tidak menemukan akses seperti itu, dan karenanya tidak menambahkan Perlindungan Halloween:

ALTER FUNCTION dbo.ReturnInput( @nilai integer)RETURNS integerWITH SCHEMABINDINGASBEGIN RETURN @value;END;GODECLARE @T AS TABLE (ProductID int PRIMARY KEY); INSERT @T (ProductID)SELECT p.ProductIDFROM AdventureWorks2012.Production.Product AS p;

Masalah dengan fungsi skalar T-SQL ini memengaruhi semua kueri pembaruan – INSERT , UPDATE , DELETE , dan MERGE . Mengetahui kapan Anda menghadapi masalah ini menjadi lebih sulit karena Perlindungan Halloween yang tidak perlu tidak akan selalu muncul sebagai Eager Table Spool tambahan, dan panggilan fungsi skalar mungkin disembunyikan dalam tampilan atau definisi kolom yang dihitung, misalnya.

[ Bagian 1 | Bagian 2 | Bagian 3 | Bagian 4 ]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dasar-dasar Ekspresi Tabel, Bagian 12 – Fungsi Bernilai Tabel Sebaris

  2. Model Data Badan Opini Publik

  3. Kompleksitas NULL – Bagian 4, Batasan unik standar tidak ada

  4. Kiat UniVerse

  5. Cara Menemukan Nilai Duplikat dalam Tabel SQL