Ketika saya berada di Chicago beberapa minggu yang lalu untuk salah satu Acara Immersion kami, seorang peserta memiliki pertanyaan statistik. Saya tidak akan membahas semua detail seputar masalah ini, tetapi peserta menyebutkan bahwa statistik diperbarui menggunakan sp_updatestats
. Ini adalah metode untuk memperbarui statistik yang tidak pernah saya rekomendasikan; Saya selalu merekomendasikan kombinasi pembangunan kembali indeks dan UPDATE STATISTICS
untuk menjaga statistik tetap up to date. Jika Anda tidak terbiasa dengan sp_updatestats
, ini adalah perintah yang dijalankan untuk seluruh database untuk memperbarui statistik. Tapi seperti yang ditunjukkan Kimberly kepada peserta, sp_updatestats
akan memperbarui statistik selama ada satu baris yang dimodifikasi. Wah. Saya segera membuka Buku Online, dan untuk sp_updatestats
Anda akan melihat ini:
Sekarang, saya akui, saya membuat asumsi tentang apa yang dimaksud dengan "...memerlukan pembaruan berdasarkan informasi rowmodctr dalam tampilan katalog sys.sysindexes...". Saya berasumsi bahwa keputusan pembaruan akan mengikuti logika yang sama dengan opsi Statistik Pembaruan Otomatis, yaitu:
- Ukuran tabel telah berubah dari 0 menjadi>0 baris (pengujian 1).
- Jumlah baris dalam tabel saat statistik dikumpulkan adalah 500 atau kurang, dan colmodctr kolom utama objek statistik telah berubah lebih dari 500 sejak saat itu (pengujian 2).
- Tabel memiliki lebih dari 500 baris saat statistik dikumpulkan, dan colmodctr kolom utama objek statistik telah berubah lebih dari 500 + 20% dari jumlah baris dalam tabel saat statistik dikumpulkan ( tes 3).
Logika ini tidak diikuti untuk sp_updatestats
. Faktanya, logikanya sangat sederhana, menakutkan:Jika satu baris diubah, statistik diperbarui. Satu baris. SATU BARIS. Apa yang menjadi perhatian saya? Saya khawatir tentang biaya pembaruan statistik untuk sekumpulan statistik yang tidak benar-benar perlu diperbarui. Mari kita lihat lebih dekat sp_updatestats
.
Kami akan memulai dengan salinan baru dari database AdventureWorks2012 yang dapat Anda unduh dari Codeplex. Pertama-tama saya akan memperbarui baris dalam tiga tabel berbeda:
USE [AdventureWorks2012]; GO SET NOCOUNT ON; GO UPDATE [Production].[Product] SET [Name] = 'Bike Chain' WHERE [ProductID] = 952; UPDATE [Person].[Person] SET [LastName] = 'Cameron' WHERE [LastName] = 'Diaz'; GO INSERT INTO Sales.SalesReason (Name, ReasonType, ModifiedDate) VALUES('Stats', 'Test', GETDATE()); GO 10000
Kami memodifikasi satu baris di Production.Product
, 211 baris dalam Person.Person
, dan kami menambahkan 10.000 baris ke Sales.SalesReason
. Jika sp_updatestats
prosedur mengikuti logika yang sama untuk pembaruan sebagai opsi Statistik Pembaruan Otomatis, kemudian hanya Sales.SalesReason
akan diperbarui karena memiliki 10 baris untuk memulai (sedangkan 211 baris diperbarui di Person.Person
mewakili sekitar satu persen dari tabel). Namun, jika kita menggali sp_updatestats
, kita dapat melihat bahwa logika yang digunakan berbeda. Perhatikan bahwa saya hanya mengekstrak pernyataan dari dalam sp_updatestats
yang digunakan untuk menentukan statistik apa yang diperbarui.
Kursor beralih melalui semua tabel yang ditentukan pengguna dan tabel internal dalam database:
declare ms_crs_tnames cursor local fast_forward read_only for select name, object_id, schema_id, type from sys.objects o where o.type = 'U' or o.type = 'IT' open ms_crs_tnames fetch next from ms_crs_tnames into @table_name, @table_id, @sch_id, @table_type
Kursor lain menelusuri statistik untuk setiap tabel, dan mengecualikan tumpukan dan indeks serta statistik hipotetis. Perhatikan bahwa sys.sysindexes
digunakan di sp_helpstats
. Sysindexes
adalah tabel sistem SQL Server 2000 dan dijadwalkan untuk dihapus dalam versi SQL Server yang akan datang. Ini menarik, karena metode lain untuk menentukan baris yang diperbarui adalah sys.dm_db_stats_properties
DMF, yang hanya tersedia di SQL 2008 R2 SP2 dan SQL 2012 SP1.
set @index_names = cursor local fast_forward read_only for select name, indid, rowmodctr from sys.sysindexes where id = @table_id and indid > 0 and indexproperty(id, name, 'ishypothetical') = 0 order by indid
Setelah sedikit persiapan dan logika tambahan, kita sampai pada IF
pernyataan yang mengungkapkan bahwa sp_updatestats
memfilter statistik yang belum memiliki baris yang diperbarui… mengonfirmasi bahwa meskipun hanya satu baris yang diubah, statistik akan diperbarui. Ada juga tanda centang untuk @is_ver_current
, yang ditentukan oleh fungsi internal bawaan.
if ((@ind_rowmodctr <> 0) or ((@is_ver_current is not null) and (@is_ver_current = 0)))
Beberapa pemeriksaan lagi terkait dengan pengambilan sampel dan tingkat kompatibilitas, lalu UPDATE
pernyataan dijalankan untuk statistik. Sebelum kita benar-benar menjalankan sp_updatestats, kita dapat menanyakan sys.sysindexes
untuk melihat statistik apa yang akan diperbarui:
SELECT [o].[name], [si].[indid], [si].[name], [si].[rowmodctr], [si].[rowcnt], [o].[type] FROM [sys].[objects] [o] JOIN [sys].[sysindexes] [si] ON [o].[object_id] = [si].[id] WHERE ([o].[type] = 'U' OR [o].[type] = 'IT') AND [si].[indid] > 0 AND [si].[rowmodctr] <> 0 ORDER BY [o].[type] DESC, [o].[name];
Selain tiga tabel yang kami modifikasi, ada statistik lain untuk tabel pengguna (dbo.DatabaseLog
) dan tiga statistik internal yang akan diperbarui:
Statistik yang akan diperbarui
Jika kita menjalankan sp_updatestats
untuk database AdventureWorks, output mencantumkan setiap tabel dan statistik yang diperbarui. Output di bawah ini dimodifikasi untuk hanya menampilkan statistik yang diperbarui:
Memperbarui [sys].[fulltext_avdl_1589580701]
[clust] telah diperbarui…
1 indeks/statistik telah diperbarui, 0 tidak memerlukan pembaruan.
…
Memperbarui [dbo].[DatabaseLog]
[PK_DatabaseLog_DatabaseLogID] telah diperbarui…
1 indeks/statistik telah diperbarui, 0 tidak memerlukan pembaruan.
…
Memperbarui [sys].[fulltext_avdl_1077578877]
[clust] telah diperbarui…
1 indeks/statistik telah diperbarui, 0 tidak memerlukan pembaruan.
…
Memperbarui [Orang].[Orang]
[PK_Person_BusinessEntityID], pembaruan tidak diperlukan…
[IX_Person_LastName_FirstName_MiddleName] telah diperbarui…
[AK_Person_rowguid], pembaruan tidak diperlukan…
1 indeks/statistik telah diperbarui, 2 tidak memerlukan pembaruan.
…
Memperbarui [Penjualan].[SalesReason]
[PK_SalesReason_SalesReasonID] telah diperbarui…
1 indeks/statistik telah diperbarui, 0 tidak memerlukan pembaruan.
…
Memperbarui [Produksi].[Produk]
[PK_Product_ProductID], tidak perlu memperbarui…
[AK_Product_ProductNumber], tidak perlu memperbarui…
[AK_Product_Name] telah diperbarui…
[ AK_Product_rowguid], pembaruan tidak diperlukan…
[_WA_Sys_00000013_75A278F5], pembaruan tidak diperlukan…
[_WA_Sys_00000014_75A278F5], pembaruan tidak diperlukan…
[_WA_Sys_0000000D_75A278F5], pembaruan tidak diperlukan…
[_WA_Sys_0000000D_75A278F5]>[_WA_Sys_0000000C_75A278F5], pembaruan tidak diperlukan…
1 indeks/statistik telah diperbarui, 7 tidak memerlukan pembaruan.
…
Statistik untuk semua tabel telah diperbarui.
Baris terakhir dari output agak menyesatkan – statistik untuk semua tabel belum diperbarui, hanya statistik yang memiliki satu baris atau lebih yang dimodifikasi telah diperbarui. Dan lagi, kekurangannya adalah mungkin sumber daya yang digunakan tidak perlu. Jika statistik hanya memiliki satu baris yang dimodifikasi, haruskah diperbarui? Tidak. Jika 10.000 baris diperbarui, haruskah diperbarui? Yah, itu tergantung. Jika tabel hanya memiliki 5.000 baris, maka mutlak; jika tabel memiliki 1 juta baris, maka tidak, karena hanya satu persen dari tabel yang telah dimodifikasi.
Kesimpulannya di sini adalah jika Anda menggunakan sp_updatestats
untuk memperbarui statistik Anda, kemungkinan besar Anda membuang-buang sumber daya, termasuk CPU, I/O, dan tempdb. Lebih lanjut, dibutuhkan waktu untuk memperbarui setiap statistik, dan jika Anda memiliki jendela pemeliharaan yang ketat, Anda mungkin memiliki tugas pemeliharaan lain yang dapat dijalankan pada waktu itu, alih-alih pembaruan yang tidak perlu. Terakhir, Anda mungkin tidak memberikan manfaat kinerja apa pun dengan memperbarui statistik ketika hanya sedikit baris yang berubah. Perubahan distribusi kemungkinan tidak signifikan jika hanya sebagian kecil baris yang telah dimodifikasi, sehingga nilai histogram dan densitas tidak berubah terlalu banyak. Selain itu, ingat bahwa memperbarui statistik membatalkan rencana kueri yang menggunakan statistik tersebut. Ketika kueri tersebut dieksekusi, rencana dibuat ulang, dan rencana tersebut mungkin akan sama persis seperti sebelumnya, karena tidak ada perubahan signifikan dalam histogram. Ada biaya untuk mengompilasi ulang rencana kueri – hal ini tidak selalu mudah diukur, tetapi tidak boleh diabaikan.
Metode yang lebih baik untuk mengelola statistik – karena Anda memang perlu mengelola statistik – adalah dengan menerapkan tugas terjadwal yang diperbarui berdasarkan persentase baris yang telah dimodifikasi. Anda dapat menggunakan kueri yang disebutkan di atas yang menginterogasi sys.sysindexes
, atau Anda dapat menggunakan kueri di bawah ini yang memanfaatkan DMF baru yang ditambahkan di SQL Server 2008 R2 SP2 dan SQL Server 2012 SP1:
SELECT [sch].[name] + '.' + [so].[name] AS [TableName] , [ss].[name] AS [Statistic], [sp].[last_updated] AS [StatsLastUpdated] , [sp].[rows] AS [RowsInTable] , [sp].[rows_sampled] AS [RowsSampled] , [sp].[modification_counter] AS [RowModifications] FROM [sys].[stats] [ss] JOIN [sys].[objects] [so] ON [ss].[object_id] = [so].[object_id] JOIN [sys].[schemas] [sch] ON [so].[schema_id] = [sch].[schema_id] OUTER APPLY [sys].[dm_db_stats_properties]([so].[object_id], [ss].[stats_id]) sp WHERE [so].[type] = 'U' AND [sp].[modification_counter] > 0 ORDER BY [sp].[last_updated] DESC;
Sadarilah bahwa tabel yang berbeda mungkin memiliki ambang batas yang berbeda dan Anda perlu mengubah kueri di atas untuk database Anda. Untuk beberapa tabel, menunggu hingga 15% atau 20% dari baris telah dimodifikasi mungkin tidak masalah. Tetapi untuk yang lain, Anda mungkin perlu memperbarui 10% atau bahkan 5%, tergantung pada nilai aktual dan kemiringannya. Tidak ada peluru perak. Sebanyak yang kami suka absolut, mereka jarang ada di SQL Server dan statistik tidak terkecuali. Anda masih ingin membiarkan Statistik Pembaruan Otomatis diaktifkan - ini adalah keamanan yang akan muncul jika Anda melewatkan sesuatu, seperti Pertumbuhan Otomatis untuk file database Anda. Namun taruhan terbaik Anda adalah mengetahui data Anda, dan menerapkan metodologi yang memungkinkan Anda memperbarui statistik berdasarkan persentase baris yang diubah.