Melanjutkan seri artikel saya tentang kait, kali ini saya akan membahas kait DBCC_OBJECT_METADATA dan menunjukkan bagaimana hal itu dapat menjadi hambatan utama untuk pemeriksaan konsistensi sebelum SQL Server 2016 dalam keadaan tertentu. Masalah ini memengaruhi DBCC CHECKDB, DBCC CHECKTABLE, dan DBCC CHECKFILEGROUP, tetapi untuk kejelasan, saya hanya akan merujuk DBCC CHECKDB untuk sisa postingan ini.
Anda mungkin bertanya-tanya mengapa saya menulis tentang masalah yang memengaruhi versi yang lebih lama, tetapi masih ada banyak SQL Server 2014 dan contoh yang lebih lama di luar sana, jadi ini adalah topik yang valid untuk seri saya.
Saya sangat menyarankan Anda membaca posting awal dalam seri sebelum yang satu ini, sehingga Anda memiliki semua latar belakang pengetahuan umum tentang kait.
Apa Itu DBCC_OBJECT_METADATA Latch?
Untuk menjelaskan kait ini, saya perlu menjelaskan sedikit tentang cara kerja DBCC CHECKDB.
Di antara sejumlah besar pemeriksaan konsistensi yang dilakukan DBCC CHECKDB adalah pemeriksaan kebenaran indeks nonclustered. Secara khusus, DBCC CHECKDB memastikan:
- Untuk setiap record indeks nonclustered di setiap indeks nonclustered, ada tepat satu record data yang "cocok" di tabel dasar (baik heap atau indeks clustered)
- Untuk setiap record data dalam tabel, ada tepat satu record indeks nonclustered yang "cocok" di setiap indeks nonclustered yang ditentukan untuk tabel, dengan mempertimbangkan indeks yang difilter
Tanpa terlalu mendalami detail tentang bagaimana hal ini dilakukan, untuk setiap record data dalam sebuah tabel, DBCC CHECKDB membangun setiap record indeks nonclustered yang harus ada untuk setiap indeks nonclustered dan memastikan record indeks nonclustered yang dibangun sama persis dengan yang sebenarnya. catatan indeks nonclustered. Jika indeks nonclustered memiliki kolom yang dihitung di dalamnya (baik sebagai bagian dari kunci indeks nonclustered atau sebagai kolom TERMASUK), DBCC CHECKDB harus mencari tahu nilai kolom yang dihitung untuk digunakan saat membuat catatan indeks.
Serta pemeriksaan kebenaran indeks nonclustered, jika ada bertahan kolom yang dihitung dalam definisi tabel, kemudian untuk setiap catatan data dalam tabel, DBCC CHECKDB harus memeriksa apakah nilai yang dipertahankan sudah benar, terlepas dari apakah kolom tersebut merupakan bagian dari indeks nonclustered atau tidak.
Jadi bagaimana cara mengetahui nilai kolom yang dihitung?
Pemroses Kueri menyediakan mekanisme untuk menghitung nilai kolom yang dihitung, yang disebut "penilai ekspresi". DBCC CHECKDB memanggil fungsi itu, memberikan informasi metadata yang sesuai dan catatan data, dan penilai ekspresi menggunakan definisi yang tersimpan dari kolom yang dihitung dalam metadata dan nilai-nilai dari catatan data dan mengembalikan nilai kolom yang dihitung untuk digunakan DBCC CHECKDB . Cara kerja internal evaluator ekspresi berada di luar kendali kode DBCC, tetapi untuk dapat menggunakan evaluator ekspresi, kunci harus diperoleh terlebih dahulu; kait DBCC_OBJECT_METADATA.
Bagaimana Kait Menjadi Penghalang?
Inilah masalahnya:hanya ada satu mode yang dapat diterima di mana kait DBCC_OBJECT_METADATA dapat diperoleh sebelum menggunakan evaluator ekspresi, dan itu adalah mode EX (eksklusif). Dan seperti yang akan Anda ketahui dari membaca postingan intro serial ini, hanya satu utas pada satu waktu yang dapat menahan kait dalam mode EX.
Menarik semua informasi ini bersama-sama:ketika database memiliki kolom yang dihitung, atau indeks nonclustered yang telah menghitung kolom di dalamnya, evaluator ekspresi harus digunakan. Jika edisi SQL Server adalah Enterprise, DBCC CHECKDB dapat menggunakan paralelisme dan memiliki banyak utas yang melakukan berbagai pemeriksaan. Dan segera setelah Anda memiliki beberapa utas yang mencoba mendapatkan kait dalam mode EX, kait itu menjadi hambatan. Seberapa besar hambatannya tergantung pada seberapa banyak evaluator ekspresi perlu digunakan, jadi semakin banyak kolom yang dihitung atau indeks nonclustered menggunakan kolom yang dihitung, dan semakin besar jumlah baris tabel di tabel tersebut, semakin semakin besar hambatan yang menjadi DBCC _OBJECT_METADATA latch.
Tapi ingat, kemacetan ini hanya terjadi untuk versi SQL Server yang lebih awal dari SQL Server 2016. Di SQL Server 2016 Microsoft memutuskan untuk "memperbaiki" kemacetan dengan mematikan pemeriksaan indeks nonclustered menggunakan kolom yang dihitung secara default dan hanya melakukannya saat WITH Opsi EXTENDED_LOGICAL_CHECKS digunakan.
Menunjukkan Kemacetan
Anda dapat dengan mudah mereproduksi kemacetan untuk diri Anda sendiri dengan menjalankan DBCC CHECKDB pada database yang memiliki kolom terkomputasi atau indeks nonclustered dengan kolom terkomputasi di dalamnya, dan database AdventureWorks yang disediakan Microsoft adalah contoh yang bagus. Anda dapat mengunduh cadangan AdventureWorks untuk versi SQL Server Anda dari sini. Saya menjalankan beberapa pengujian menggunakan database AdventureWorks2014 pada instance SQL Server 2014 (pada Dell R720) 32-core, dan saya memperbesar database menjadi beberapa ratus GB menggunakan skrip Jonathan.
Ketika saya menjalankan DBCC CHECKDB, dengan server MAXDOP disetel ke 0, butuh lebih dari 5 jam untuk dijalankan. Jenis menunggu LATCH_EX menyumbang sekitar 30% dari menunggu, dengan setiap menunggu hanya berjarak 1 milidetik, dan 99% dari LATCH_EX menunggu adalah untuk kait DBCC_OBJECT_METADATA.
Saya mencari indeks nonclustered yang berisi kolom yang dihitung menggunakan kode berikut:
SELECT [s].[name] AS [Schema], [o].[name] AS [Object], [i].[name] AS [Index], [c].[name] AS [Column] ], [ic].* DARI sys.columns [c] GABUNG sys.index_columns [ic] ON [ic].[object_id] =[c].[object_id] DAN [ic].[column_id] =[c]. [column_id] GABUNG sys.indexes [i] ON [i].[object_id] =[ic].[object_id] AND [i].[index_id] =[ic].[index_id] GABUNG sys.objects [o] ON [i].[object_id] =[o].[object_id] GABUNG sys.schemas [s] ON [o].[schema_id] =[s].[schema_id] WHERE [c].[is_computed] =1;Kode itu menemukan enam indeks nonclustered di database AdventureWorks2014. Saya menonaktifkan keenam indeks (menggunakan ALTER INDEX ... DISABLE) dan menjalankan kembali DBCC CHECKDB dan selesai dalam waktu sekitar 18 menit. Jadi hambatan kait DBCC_OBJECT_METADATA adalah faktor utama yang menyebabkan DBCC CHECKDB berjalan lebih dari 16 kali lebih lambat!
Ringkasan
Sayangnya, menonaktifkan indeks nonclustered menggunakan kolom yang dihitung (dan kemudian mengaktifkannya kembali menggunakan ALTER INDEX ... REBUILD) adalah *satu-satunya* cara untuk menghapus hambatan kait DBCC_OBJECT_METADATA di versi sebelum SQL Server 2016 sambil tetap mempertahankan semua fungsi lain dari DBCC CHECKDB. Menonaktifkan indeks nonclustered kemungkinan bukan sesuatu yang ingin Anda lakukan di lingkungan produksi kecuali Anda memiliki jendela pemeliharaan aktivitas nol. Ini berarti Anda mungkin hanya akan menonaktifkan indeks nonclustered tersebut untuk menghilangkan hambatan jika pemeriksaan konsistensi Anda dipindahkan ke server lain menggunakan metode backup-copy-restore-CHECKDB.
Cara lain untuk melakukannya adalah dengan menggunakan opsi WITH PHYSICAL_ONLY saat menjalankan DBCC CHECKDB tetapi kemudian Anda melewatkan semua pemeriksaan logis yang mendalam, jadi saya tidak terlalu merekomendasikannya sebagai solusi.