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

Tampilan Terindeks dan Statistik

Tampilan terindeks dapat dibuat dalam edisi SQL Server apa pun, tetapi ada sejumlah perilaku yang harus diperhatikan jika Anda ingin memanfaatkannya sebaik mungkin.

Statistik otomatis memerlukan petunjuk NOEXPAND

SQL Server dapat membuat statistik secara otomatis untuk membantu estimasi kardinalitas dan pengambilan keputusan berbasis biaya selama pengoptimalan kueri. Fitur ini berfungsi dengan tampilan yang diindeks serta tabel dasar, tetapi hanya jika tampilan secara eksplisit dinamai dalam kueri dan NOEXPAND petunjuk ditentukan. (Selalu ada objek statistik yang terkait dengan setiap indeks pada tampilan, itu adalah pembuatan otomatis dan pemeliharaan statistik yang tidak terkait dengan indeks yang sedang kita bicarakan di sini.)

Jika Anda terbiasa bekerja dengan SQL Server edisi non-Enterprise, Anda mungkin tidak pernah memperhatikan perilaku ini sebelumnya. Edisi SQL Server yang lebih rendah memerlukan NOEXPAND petunjuk untuk menghasilkan rencana kueri yang mengakses tampilan yang diindeks. Ketika NOEXPAND ditentukan, statistik otomatis dibuat pada tampilan yang diindeks persis seperti yang terjadi pada tabel biasa.

Contoh – Edisi Standar dengan NOEXPAND

Menggunakan SQL Server 2012 Standard Edition dan database sampel Adventure Works, pertama-tama kita membuat tampilan yang menggabungkan dua tabel penjualan dan menghitung total jumlah pesanan per pelanggan dan produk:

BUAT TAMPILAN dbo.PesananPelangganDENGAN SCHEMABINDING ASSELECT SOH.CustomerID, SOD.ProductID, OrderQty =SUM(SOD.OrderQty), NumRows =COUNT_BIG(*)FROM Sales.SalesOrderDetail AS SODJOIN Sales.SalesOrderHeader AS =SODOrderHeader AS .SalesOrderIDGROUP OLEH SOH.CustomerID, SOD.ProductID;

Agar tampilan ini mendukung statistik, kita perlu mewujudkannya dengan menambahkan indeks berkerumun yang unik. Kombinasi ID Pelanggan dan Produk dijamin unik dalam tampilan (menurut definisi) sehingga kami akan menggunakannya sebagai kunci. Kami dapat menentukan dua kolom dalam indeks, tetapi dengan asumsi kami mengharapkan lebih banyak kueri untuk memfilter menurut produk, kami menjadikan ID Produk sebagai kolom utama. Tindakan ini juga membuat statistik indeks, dengan histogram yang dibuat dari nilai ID Produk.

BUAT UNIK CLUSTERED INDEX cuq PADA dbo.CustomerOrders (ProductID, CustomerID);

Kami sekarang diminta untuk menulis kueri yang menunjukkan jumlah total pesanan per pelanggan, untuk rentang produk tertentu. Kami berharap bahwa rencana eksekusi menggunakan tampilan terindeks akan menjadi strategi yang efektif, karena akan menghindari penggabungan dan pengoperasian pada data yang sudah dikumpulkan sebagian. Karena kita menggunakan SQL Server Standard Edition, kita harus menentukan tampilan secara eksplisit dan menggunakan NOEXPAND petunjuk untuk menghasilkan rencana kueri yang mengakses tampilan yang diindeks:

PILIH CO.CustomerID, SUM(CO.OrderQty)FROM dbo.CustomerOrders AS CO WITH (NOEXPAND)WHERE CO.ProductID ANTARA 711 DAN 718GROUP OLEH CO.CustomerID;

Rencana eksekusi yang dihasilkan menunjukkan pencarian pada tampilan yang diindeks untuk menemukan baris produk yang diminati diikuti dengan agregasi untuk menghitung jumlah total per pelanggan:

Tampilan Plan Tree dari SQL Sentry Plan Explorer menunjukkan estimasi kardinalitas benar-benar tepat untuk pencarian tampilan yang diindeks, dan sangat baik untuk hasil agregat:

Sebagai bagian dari proses kompilasi dan pengoptimalan untuk kueri ini, SQL Server membuat objek statistik tambahan di kolom ID Pelanggan dari tampilan yang diindeks. Statistik ini dibuat karena jumlah dan distribusi ID Pelanggan yang diharapkan mungkin penting, misalnya dalam memilih strategi agregasi. Kita dapat melihat statistik baru menggunakan Management Studio Object Explorer:

Mengklik dua kali objek statistik mengonfirmasi bahwa objek tersebut dibuat dari kolom ID Pelanggan pada tampilan (bukan tabel dasar):

Tampilan Terindeks dapat meningkatkan Estimasi Kardinalitas

Masih menggunakan Edisi Standar, sekarang kami menghapus dan membuat ulang tampilan yang diindeks (yang juga menghapus statistik tampilan) dan menjalankan kueri lagi, kali ini dengan NOEXPAND petunjuk berkomentar:

PILIH CO.CustomerID, SUM(CO.OrderQty)FROM dbo.CustomerOrders AS CO --DENGAN (NOEXPAND)WHERE CO.ProductID ANTARA 711 DAN 718GROUP OLEH CO.CustomerID;

Seperti yang diharapkan saat menggunakan Edisi Standar tanpa NOEXPAND , rencana kueri yang dihasilkan beroperasi pada tabel dasar daripada tampilan secara langsung:

Segitiga peringatan pada operator root dalam rencana di atas mengingatkan kita pada indeks yang berpotensi berguna pada tabel Detail Pesanan Penjualan, yang tidak penting untuk tujuan kita saat ini. Kompilasi ini tidak membuat statistik apa pun pada tampilan yang diindeks. Satu-satunya statistik pada tampilan setelah kompilasi kueri adalah yang terkait dengan indeks berkerumun:

Tampilan Plan Tree untuk kueri menunjukkan bahwa estimasi kardinalitas benar untuk dua pemindaian tabel dan gabungan, tetapi sedikit lebih buruk untuk operator paket lainnya:

Menggunakan tampilan yang diindeks dengan NOEXPAND petunjuk menghasilkan perkiraan yang lebih akurat untuk kueri pengujian kami karena informasi kualitas yang lebih baik tersedia dari statistik tampilan – khususnya, statistik yang terkait dengan indeks tampilan.

Sebagai aturan umum, keakuratan informasi statistik menurun cukup cepat saat melewati dan dimodifikasi oleh operator rencana kueri. Gabungan sederhana seringkali tidak terlalu buruk dalam hal ini, tetapi informasi tentang hasil agregasi seringkali tidak lebih baik daripada tebakan yang terpelajar. Menyediakan pengoptimal kueri dengan informasi yang lebih akurat menggunakan statistik pada tampilan yang diindeks dapat menjadi teknik yang berguna untuk meningkatkan kualitas dan ketahanan rencana.

Tampilan tanpa NOEXPAND dapat menghasilkan denah yang lebih rendah

Paket kueri yang ditampilkan di atas (Edisi Standar, tanpa NOEXPAND ) sebenarnya kurang optimal dibandingkan jika kita sendiri yang menulis kueri terhadap tabel dasar, daripada mengizinkan pengoptimal kueri untuk memperluas tampilan. Kueri di bawah ini menyatakan persyaratan logis yang sama, tetapi tidak mereferensikan tampilan:

PILIH SOH.CustomerID, SUM(OrderQty)FROM Sales.SalesOrderHeader AS SOHJOIN Sales.SalesOrderDetail AS SOD ON SOD.SalesOrderID =SOH.SalesOrderIDWHERE SOD.ProductID ANTARA 711 DAN 718GROUP BY SOH.CustomerID;

Kueri ini menghasilkan rencana eksekusi berikut:

Paket ini menampilkan satu operasi agregasi yang lebih sedikit daripada sebelumnya. Saat perluasan tampilan digunakan, pengoptimal kueri sayangnya tidak dapat menghapus operasi agregasi yang berlebihan, sehingga menghasilkan rencana eksekusi yang kurang efisien. Perkiraan kardinalitas akhir untuk kueri baru juga sedikit lebih baik daripada saat tampilan yang diindeks direferensikan tanpa NOEXPAND :

Namun demikian, perkiraan terbaik tetap dihasilkan saat mereferensikan tampilan yang diindeks dengan NOEXPAND (diulang di bawah untuk kenyamanan):

Edisi Perusahaan dan Pencocokan Tampilan

Pada instans Edisi Perusahaan, pengoptimal kueri mungkin dapat menggunakan tampilan yang diindeks meskipun kueri tidak menyebutkan tampilan secara eksplisit. Jika pengoptimal dapat mencocokkan bagian dari pohon kueri ke tampilan yang diindeks, pengoptimal dapat memilih untuk melakukannya, berdasarkan estimasi biaya penggunaan tampilan atau tidak. Logika pencocokan tampilan cukup pintar, tetapi memiliki batasan yang cukup mudah untuk dicapai dalam praktik. Meskipun pencocokan tampilan berhasil, pengoptimal masih dapat disesatkan oleh perkiraan biaya yang tidak akurat.

Petunjuk kueri EXPAND VIEWS

Dimulai dengan kemungkinan yang lebih jarang, mungkin ada saat-saat di mana kueri merujuk tampilan yang diindeks, tetapi rencana yang lebih baik akan diperoleh dengan mengakses tabel dasar sebagai gantinya. Dalam keadaan ini, petunjuk kueri EXPAND VIEWS dapat digunakan:

PILIH CO.CustomerID, SUM(CO.OrderQty)FROM dbo.CustomerOrders SEBAGAI COWHERE CO.ProductID ANTARA 711 DAN 718GROUP OLEH CO.CustomerIDOPTION (PERLUAS TAMPILAN);

Pada Edisi Perusahaan, kueri ini menghasilkan paket yang sama seperti yang terlihat pada Edisi Standar saat NOEXPAND petunjuk dihilangkan (termasuk operasi agregasi redundan):

Selain itu, EXPAND VIEWS petunjuk tidak bernama buruk, menurut pendapat saya. SQL Server selalu memperluas definisi tampilan dalam kueri kecuali NOEXPAND petunjuk ditentukan. EXPAND VIEWS petunjuk menonaktifkan aturan di pengoptimal yang dapat mencocokkan bagian dari pohon yang diperluas kembali ke tampilan yang diindeks. Jika tidak ada petunjuk, SQL Server pertama-tama memperluas tampilan ke definisi tabel dasarnya, kemudian mempertimbangkan untuk mencocokkan kembali ke tampilan yang diindeks. Nama yang lebih baik untuk EXPAND VIEWS petunjuk mungkin DISABLE INDEXED VIEW MATCHING , karena itulah fungsinya.

EXPAND VIEWS petunjuk mungkin paling sering digunakan untuk mencegah kueri terhadap tabel dasar agar tidak dicocokkan dengan tampilan yang diindeks:

PILIH SOH.CustomerID, SUM(OrderQty)FROM Sales.SalesOrderHeader AS SOHJOIN Sales.SalesOrderDetail AS SOD ON SOD.SalesOrderID =SOH.SalesOrderIDWHERE SOD.ProductID ANTARA 711 DAN 718GROUP MENURUT SOHEX.CustomerIDOPTION;> 

Petunjuk kueri menghasilkan rencana dan perkiraan eksekusi yang sama seperti yang terlihat saat kami menggunakan Edisi Standar dan kueri tabel-dasar yang sama:

Pencocokan dan Statistik Tampilan Perusahaan

Bahkan di Edisi Perusahaan, statistik tampilan non-indeks hanya dibuat jika NOEXPAND petunjuk digunakan. Agar benar-benar jelas tentang hal itu, fitur pencocokan tampilan khusus Perusahaan tidak pernah menghasilkan statistik tampilan yang dibuat atau diperbarui. Perilaku tidak intuitif ini perlu ditelusuri sedikit, karena dapat memiliki efek samping yang mengejutkan.

Kami sekarang menjalankan kueri dasar kami terhadap tampilan pada instance Edisi Perusahaan, tanpa petunjuk apa pun:

PILIH CO.CustomerID, SUM(CO.OrderQty)FROM dbo.CustomerOrders SEBAGAI COWHERE CO.ProductID ANTARA 711 DAN 718GROUP OLEH CO.CustomerID;

Hal baru ada segitiga peringatan pada View Clustered Index Seek. Keterangan alat menunjukkan detailnya:

Kami tidak menggunakan NOEXPAND petunjuk, jadi statistik pada kolom ID Pelanggan dari tampilan yang diindeks tidak dibuat secara otomatis. Statistik ID Pelanggan sebenarnya tidak terlalu penting dalam contoh yang disederhanakan ini, tetapi tidak selalu demikian.

Perkiraan Kardinalitas Penasaran

Hal kedua yang menarik adalah bahwa perkiraan kardinalitas tampak lebih buruk daripada kasus apa pun yang kami temui sejauh ini, termasuk contoh Edisi Standar.

Awalnya sulit untuk melihat dari mana estimasi kardinalitas untuk View Clustered Index Seek (11.267) berasal. Kami mengharapkan perkiraan didasarkan pada informasi histogram ID Produk dari statistik yang terkait dengan indeks pengelompokan tampilan. Bagian yang relevan dari histogram ini ditunjukkan di bawah ini:

DBCC SHOW_STATISTICS ('dbo.CustomerOrders', 'cuq') DENGAN HISTOGRAM;

Mengingat bahwa tabel belum diubah sejak statistik dibuat, kami mengharapkan perkiraan menjadi jumlah sederhana dari RANGE_ROWS dan EQ_ROWS untuk nilai ID Produk antara 711 dan 718 (perhatikan bahwa perkiraan harus mengecualikan 28 RANGE_ROWS yang ditampilkan terhadap entri 711 karena baris tersebut ada di bawah nilai kunci 711). Jumlah EQ_ROWS yang ditampilkan adalah 7.301. Ini persis jumlah baris yang sebenarnya ditampilkan oleh tampilan – jadi dari mana perkiraan 11.267 itu berasal?

Jawabannya terletak pada cara kerja pencocokan tampilan saat ini. Permintaan kami tidak menentukan NOEXPAND petunjuk, jadi estimasi kardinalitas awal didasarkan pada pohon kueri yang diperluas tampilan. Ini paling mudah dilihat dengan melihat kembali perkiraan paket untuk kueri yang sama dengan EXPAND VIEWS ditentukan:

Area yang diarsir merah mewakili bagian pohon yang digantikan oleh aktivitas pencocokan tampilan. Kardinalitas keluaran dari area ini adalah 11.267. Bagian yang tidak diarsir dengan perkiraan 11.220 tidak terpengaruh oleh pencocokan tampilan. Ini persis perkiraan yang ingin kami jelaskan:

Pencocokan tampilan cukup mengganti area yang diarsir merah dengan pencarian yang setara secara logis pada tampilan yang diindeks. Itu tidak menggunakan informasi statistik dari tampilan untuk menghitung ulang perkiraan kardinalitas.

Sampai batas tertentu, Anda mungkin dapat memahami mengapa ini bisa bekerja dengan cara ini:secara umum, ada sedikit alasan untuk mengharapkan bahwa perkiraan yang dihitung dari satu kumpulan informasi statistik lebih baik daripada yang lain. Sebuah kasus dapat dibuat bahwa statistik tampilan yang diindeks lebih cenderung akurat di sini, dibandingkan dengan statistik turunan pasca-gabung di area yang diarsir merah, tetapi mungkin sulit untuk menggeneralisasinya, atau dengan benar memperhitungkan seberapa cepat berbagai sumber informasi statistik mungkin kedaluwarsa karena data yang mendasarinya berubah.

Orang juga dapat berargumen bahwa jika kami sangat yakin informasi tampilan yang diindeks lebih baik, kami akan menggunakan NOEXPAND petunjuk.

Perkiraan Kardinalitas yang Lebih Menarik

Situasi yang lebih menarik muncul dengan Edisi Perusahaan jika kita menulis kueri terhadap tabel dasar dan mengandalkan pencocokan tampilan otomatis:

PILIH SOH.CustomerID, SUM(OrderQty)FROM Sales.SalesOrderHeader AS SOHJOIN Sales.SalesOrderDetail AS SOD ON SOD.SalesOrderID =SOH.SalesOrderIDWHERE SOD.ProductID ANTARA 711 DAN 718GROUP BY SOH.CustomerID;

Peringatan statistik yang hilang sama seperti sebelumnya, dan memiliki penjelasan yang sama. Fitur yang lebih menarik adalah kami sekarang memiliki perkiraan yang lebih rendah untuk jumlah baris yang dihasilkan oleh View Clustered Index Seek (7.149) dan peningkatan perkiraan untuk jumlah baris yang dikembalikan dari agregasi (8.226).

Untuk menekankan intinya, rencana kueri ini tampaknya didasarkan pada gagasan bahwa 7.149 baris sumber dapat digabungkan untuk menghasilkan 8.226 baris!

Bagian dari penjelasannya sama seperti sebelumnya. EXPAND VIEWS rencana kueri, menunjukkan wilayah merah yang akan diganti dengan pencocokan tampilan ditunjukkan di bawah ini:

Ini menjelaskan dari mana estimasi akhir 8.226 berasal, tetapi bagaimana dengan estimasi baris 7.149? Mengikuti logika yang terlihat sebelumnya, tampaknya tampilan harus menunjukkan perkiraan 11.267 baris?

Jawabannya adalah bahwa perkiraan 7.149 adalah tebakan. Ya, benar-benar. Tampilan yang diindeks berisi total 79.433 baris. Persentase tebakan ajaib untuk predikat Product ID BETWEEN adalah 9% – memberikan 0,09 * 79433 =7148,97 baris. Rencana kueri SSMS menunjukkan penghitungan ini benar-benar tepat, bahkan sebelum pembulatan:

Dalam situasi ini, pengoptimal SQL Server tampaknya lebih memilih tebakan berdasarkan kardinalitas tampilan yang diindeks daripada perkiraan kardinalitas pasca-gabung dari subpohon yang diganti. Penasaran.

Ringkasan

Menggunakan NOEXPAND petunjuk menjamin bahwa tampilan yang diindeks akan digunakan dalam rencana kueri akhir, dan memungkinkan statistik non-indeks dibuat, dipelihara, dan digunakan secara otomatis oleh pengoptimal kueri. Menggunakan NOEXPAND juga memastikan perkiraan kardinalitas awal didasarkan pada informasi tampilan yang diindeks daripada diturunkan dari tabel dasar.

Jika NOEXPAND tidak ditentukan, referensi tampilan selalu diganti dengan definisi tabel dasarnya sebelum kompilasi kueri dimulai (dan karenanya sebelum estimasi kardinalitas awal). Hanya di SKU Perusahaan, tampilan yang diindeks dapat diganti kembali ke pohon kueri nanti dalam proses pengoptimalan.

EXPAND VIEWS petunjuk kueri mencegah pengoptimal melakukan pencocokan tampilan terindeks Edisi Perusahaan. Ini berlaku apakah kueri awalnya mereferensikan tampilan yang diindeks atau tidak. Saat pencocokan tampilan dilakukan, perkiraan kardinalitas yang ada dapat diganti dengan tebakan dalam beberapa keadaan.

Statistik yang ditampilkan sebagai tidak ada pada tampilan yang diindeks dapat dibuat secara manual, tetapi pengoptimal umumnya tidak akan menggunakannya untuk kueri yang tidak menggunakan NOEXPAND petunjuk.

Menggunakan tampilan terindeks dapat meningkatkan estimasi kardinalitas, terutama jika tampilan berisi gabungan atau agregasi. Kueri memiliki peluang terbaik untuk mendapatkan manfaat dari statistik tampilan yang lebih akurat jika NOEXPAND ditentukan.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sepuluh Ancaman Umum terhadap Kualitas Rencana Eksekusi

  2. SQL, menambahkan data ke tabel

  3. Menguji Lapisan ODBC

  4. Model Data Badan Opini Publik

  5. SQL PILIH DI