Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

SQL Server Internal:Rencana Caching Pt. II – Menyusun Ulang Rencana

Ini adalah bagian dari seri Caching Paket Internal SQL Server. Pastikan untuk membaca posting pertama Kalen tentang topik ini.

SQL Server telah ada selama lebih dari 30 tahun, dan saya telah bekerja dengan SQL Server hampir selama itu. Saya telah melihat banyak perubahan selama bertahun-tahun (dan beberapa dekade!) Dan versi produk luar biasa ini. Dalam posting ini saya akan berbagi dengan Anda bagaimana saya melihat beberapa fitur atau aspek SQL Server, terkadang bersama dengan sedikit perspektif historis

Dalam artikel saya sebelumnya , saya berbicara tentang diagnostik server SQL, termasuk berbagai opsi yang dimiliki SQL Server untuk menggunakan kembali paket kueri. Kami melihat tiga jenis rencana kueri:adhoc, disiapkan, dan prosedur. Saya mengakhiri diskusi dengan melihat penggunaan kembali rencana yang tidak tepat, yang dapat terjadi ketika SQL Server menerapkan parameter sniffing dalam situasi yang salah. Jika rencana didasarkan pada nilai awal yang menyebabkan pengoptimal menghasilkan rencana yang sesuai untuk nilai tersebut, dan kemudian rencana yang sama digunakan untuk nilai yang berbeda, rencana tersebut mungkin tidak lagi optimal.

Jadi, apa yang bisa kita lakukan ketika parameter sniffing menjadi masalah? Kami dapat memaksa SQL Server untuk membuat rencana baru. Biasanya, kami menyebut tindakan membuat rencana baru sebagai 'kompilasi ulang', tetapi mungkin harus disebut 'mengoptimalkan ulang'. Namun, kebanyakan orang menggunakan istilah 'kompilasi ulang', jadi itulah yang akan saya gunakan di sini.

Jika penggunaan parameter sniffing yang tidak tepat menjadi masalah, solusi sederhana adalah dengan memberi tahu SQL Server untuk membuat rencana baru. Untuk pernyataan individual, seperti dengan paket SIAPKAN yang telah diparameterisasi otomatis, kami dapat menambahkan petunjuk RECOMPILE ke kueri. Menggunakan parameter FORCED (dibahas dalam artikel sebelumnya), kueri ini akan diparameterisasi.

SELECT * FROM dbo.newsales 
WHERE SalesOrderID < @num;

Jika kita ingin memastikan bahwa kita mendapatkan rencana baru setiap kali kita menjalankan kueri ini, dengan nilai yang berpotensi sangat berbeda untuk @num, kita dapat menambahkan petunjuk RECOMPILE seperti yang ditunjukkan:

SELECT * FROM dbo.newsales
  WHERE SalesOrderID < @num
OPTION (RECOMPILE);

Untuk prosedur tersimpan, kami memiliki tiga opsi. Pertama, kita dapat memastikan apakah kompilasi ulang akan benar-benar membantu kinerja dengan menjalankan prosedur dengan opsi RECOMPILE:

EXEC get_sales_range 66666 WITH RECOMPILE;

Opsi ini akan menyebabkan rencana baru dibuat hanya untuk satu eksekusi ini. Itu tidak akan disimpan dan tentu saja tidak akan digunakan kembali. Nilai usecount yang ditampilkan di sp_cacheobjects (dijelaskan dalam posting sebelumnya) untuk prosedur tidak akan meningkat karena rencana awal tidak digunakan kembali.

Kedua, jika kami menemukan bahwa mengeksekusi WITH RECOMPILE membantu, kami dapat mempertimbangkan untuk membuat ulang prosedur dengan opsi RECOMPILE, dalam hal ini tidak akan pernah menggunakan kembali paket dan prosedur tidak akan muncul di cache paket sama sekali.

DROP PROC IF EXISTS get_sales_range;GO
CREATE PROC get_sales_range
   @num int
WITH RECOMPILE
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num;
GO

Untuk prosedur kecil saya yang sederhana, menggunakan opsi WITH RECOMPILE untuk seluruh prosedur mungkin masuk akal. Tetapi jika prosedurnya lebih kompleks, mungkin tidak masuk akal untuk mengkompilasi ulang seluruh prosedur karena satu pernyataan menyebabkan masalah. Jadi, opsi ketiga adalah menggunakan petunjuk RECOMPILE untuk pernyataan di dalam prosedur, sehingga terlihat seperti ini:

DROP PROC IF EXISTS get_sales_range;
GO
CREATE PROC get_sales_range
   @num int
AS
    SELECT * FROM dbo.newsales
    WHERE SalesOrderID < @num
    OPTION (RECOMPILE);
GO

Menggunakan salah satu opsi RECOMPILE ini dapat memaksa SQL Server untuk membuat rencana baru atas permintaan Anda. Sekarang, kita akan melihat kapan diagnostik SQL Server Anda muncul dengan paket baru saat Anda tidak memintanya, yaitu kapan kompilasi ulang otomatis dari paket yang ada terjadi?


Kompilasi ulang otomatis rencana terjadi dalam dua jenis situasi:

  • Pertama, jika pengoptimal menentukan bahwa rencana yang ada tidak lagi benar, biasanya karena perubahan definisi objek, ia perlu membuat rencana baru. Misalnya, jika Anda memiliki rencana untuk kueri yang memilih dari TableA, dan Anda kemudian menjatuhkan beberapa kolom, atau mengubah tipe data kolom di TableA, SQL Server akan mengkompilasi ulang kueri untuk menghasilkan rencana yang mencerminkan perubahan DDL.
  • Situasi kedua di mana kompilasi ulang otomatis terjadi adalah ketika SQL Server menentukan bahwa rencana mungkin tidak lagi optimal, karena perubahan statistik. Dalam kebanyakan kasus, jika statistik pada salah satu kolom atau indeks telah diperbarui sejak terakhir kali rencana itu dikompilasi, itu akan dikompilasi ulang. Tapi ini mengarah ke pertanyaan lain. Kapan statistik diperbarui? Statistik dapat diperbarui secara otomatis ketika cukup banyak baris di kolom yang relevan telah berubah. Berapa banyak yang cukup? Kami membicarakannya sebentar lagi.

Secara default, SQL Server akan memperbarui statistik secara otomatis karena opsi database yang AKTIF secara default. Tetapi jika Anda adalah pemilik database (atau SQL 'sa', yang muncul sebagai pemilik di setiap database), Anda dapat mengubah opsi. Salah satu opsi disebut AUTO_UPDATE_STATISTICS dan opsi lainnya disebut AUTO_UPDATE_STATISTICS_ASYNC. Opsi AUTO_UPDATE_STATISTICS AKTIF di database tempdb, jadi setiap database baru mewarisi opsi ini. Saat opsi ini AKTIF, dan mesin eksekusi kueri mendeteksi perubahan pada jumlah baris yang cukup saat kueri sedang diproses, eksekusi akan dijeda saat statistik diperbarui, lalu kueri dikompilasi ulang. Opsi lainnya, AUTO_UPDATE_STATISTICS_ASYNC, berpotensi memiliki lebih sedikit efek pada waktu eksekusi kueri karena eksekusi tidak berhenti, dengan mengorbankan kemungkinan rencana suboptimal. Dengan opsi kedua, jika mesin eksekusi mendeteksi kebutuhan untuk memperbarui statistik, utas latar belakang diaktifkan untuk melakukan pembaruan, dan utas utama terus mengeksekusi kueri dengan statistik asli dan rencana awal. Kueri berikutnya yang mengakses tabel yang terpengaruh dan melihat statistik yang diperbarui akan mengkompilasi ulang kueri, tetapi tidak akan menjeda dan melakukan pembaruan statistik di tengah eksekusi.

Ada beberapa situasi lagi serta beberapa petunjuk kueri yang mengontrol apakah rencana dikompilasi ulang atau tidak, jadi saya akan menunjukkan kepada Anda diagram alur. Saya akan membagikan diagram alur dengan Anda yang saya buat untuk kelas pelatihan saya di internal SQL Server.

Panah adalah tempat SQL Server mulai memproses kumpulan Anda. Ini pertama-tama memeriksa untuk melihat apakah sudah ada rencana untuk batch Anda di cache, dan jika jawabannya TIDAK, ikuti panah ke kanan dan kompilasi rencana. Rencana tersebut dimasukkan ke dalam cache, dan kemudian SQL Server dimulai lagi. Ya, rencananya kali ini harus disimpan dalam cache, lalu mengikuti panah ke bawah dan menanyakan apakah petunjuk yang disebut KEEP PLAN telah digunakan. Jika YA, SQL Server segera menjalankan rencana dan tidak melakukan pemeriksaan lebih lanjut.

Pertanyaan berikutnya adalah apakah ada perubahan DDL yang telah dibuat. Jika tidak, ini menanyakan tentang beberapa situasi lain yang tidak dapat saya bicarakan di artikel ini. Sebenarnya, saya tidak akan membahas setiap opsi di sini. Saya akan menyerahkan itu kepada Anda. Tetapi jika Anda memiliki pertanyaan atau kebingungan, jangan ragu untuk bertanya di bagian komentar di sini, atau tweet saya di @sqlqueen. Saya akan menunjukkan pertanyaan di paling kanan:Apakah AUTO_STATS_ASYNC AKTIF? Di sini, Anda dapat melihat bahwa jika jawabannya YA, ada dua tindakan. Satu cabang baru saja memulai eksekusi dengan rencana yang ada, dan yang lainnya adalah utas latar belakang yang memperbarui statistik tetapi kemudian tidak melakukan hal lain. Kueri berikutnya akan menemukan kotak keputusan di tengah "Apakah statistik baru tersedia" dan harus menjawab YA, sehingga kueri akan dikompilasi ulang.

Satu-satunya hal lain yang akan saya bicarakan adalah pertanyaan "Apakah ada statistik yang basi?" Ini pada dasarnya berarti statistik sudah ketinggalan zaman karena terlalu banyak perubahan yang dilakukan. Jadi sekarang kita bisa membicarakan berapa banyak yang terlalu banyak.

Meskipun ada nilai berbeda yang digunakan untuk tabel yang sangat kecil, untuk tabel apa pun dengan lebih dari 500 baris di dalamnya, sebelum SQL Server 2016, statistik akan dianggap 'basi' ketika jumlah perubahan pada kolom yang menjadi dasar statistik melebihi 20 % dari jumlah baris dalam tabel. Jadi, untuk tabel 1000 baris, ini bisa berarti 200 sisipan, 200 pembaruan, atau 200 penghapusan. Itu bisa berupa 200 baris perubahan, atau 5 baris diperbarui masing-masing 40 kali. SQL Server bahkan memberi kita fungsi yang melaporkan berapa banyak perubahan yang telah dibuat. Anda harus mencari nomor stats_id untuk statistik yang Anda minati, yang akan menjadi index_id jika statistik termasuk dalam indeks. Stats_id dapat ditemukan dalam tampilan yang disebut sys.stats. Dalam tabel penjualan baru saya, saya menggunakan kueri ini untuk menemukan bahwa stats_id untuk indeks pada kolom SubTotal adalah 3.

SELECT name, stats_id FROM sys.stats
WHERE object_id = object_id('newsales');

Kemudian saya dapat menggunakan nilai itu untuk melihat jumlah perubahan. Biarkan saya memperbarui beberapa baris terlebih dahulu:

UPDATE newsales
SET SubTotal = SubTotal * 0.9
WHERE SalesOrderID < 45200
(1541 baris terpengaruh)

SELECT * FROM sys.dm_db_stats_properties(object_id('newsales'), 3);  

Faktanya, 20% adalah angka BESAR. Dan untuk banyak tabel, kueri mungkin mendapat manfaat dari statistik yang diperbarui dengan jauh lebih sedikit dari 20% baris yang diperbarui. Mulai 2008R2 SP1, SQL Server menyertakan Traceflag yang dapat Anda gunakan untuk mengubah jumlah baris menjadi skala geser, seperti yang ditunjukkan pada grafik berikut:

Mulai SQL Server 2016, algoritme baru dengan skala geser ini digunakan secara default, selama Anda berada di tingkat kompatibilitas 130 atau lebih tinggi.

Sebagian besar kompilasi ulang otomatis dari rencana kueri disebabkan oleh perubahan statistik. Tetapi seperti yang saya sebutkan di atas, itu bukan satu-satunya alasan untuk mengkompilasi ulang. Namun karena ini adalah yang paling umum, akan sangat berguna untuk mengetahui kapan dan bagaimana statistik diperbarui dan memastikan statistik pada tabel penting Anda cukup sering diperbarui untuk memastikan Anda mendapatkan rencana terbaik!

Analisis data kinerja secara otomatis untuk melakukan diagnostik server SQL guna menyelesaikan masalah dengan cepat dan mengidentifikasi server tempat penurunan kinerja berasal. Mulai gunakan Spotlight Cloud hari ini:


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Penggunaan SQL Server sp_msforeachtable untuk memilih hanya tabel yang memenuhi beberapa kondisi

  2. Mengapa saya tidak bisa menggunakan alias dalam pernyataan DELETE?

  3. Pemeriksaan Kesehatan SQL Server Proaktif, Bagian 4:ERRORLOG

  4. Cara Menambahkan File Log ke Database SQL Server (T-SQL)

  5. Cara Menggunakan GOTO di SQL Server