Dalam artikel saya sebelumnya, saya telah membahas secara singkat statistik basis data, pentingnya, dan mengapa statistik harus diperbarui. Selain itu, saya telah menunjukkan proses langkah demi langkah untuk membuat rencana pemeliharaan SQL Server untuk memperbarui statistik. Pada artikel ini akan dijelaskan masalah-masalah berikut:1. Cara mengupdate statistik menggunakan Perintah T-SQL. 2. Bagaimana mengidentifikasi tabel yang sering diupdate menggunakan T-SQL dan juga bagaimana mengupdate statistik tabel dengan data yang sering disisipkan/diperbarui/dihapus.
Memperbarui statistik menggunakan T-SQL
Anda dapat memperbarui statistik menggunakan skrip T-SQL. Jika Anda ingin memperbarui statistik menggunakan T-SQL atau SQL Server management studio, Anda memerlukan ALTER database izin pada database. Lihat contoh kode T-SQL untuk memperbarui statistik tabel tertentu:
UPDATE STATISTICS <schema_name>.<table_name>.
Mari kita perhatikan contoh memperbarui statistik OrderLines tabel WideWorldImporters basis data. Skrip berikut akan melakukannya.
UPDATE STATISTICS [Sales].[OrderLines]
Jika Anda ingin memperbarui statistik indeks tertentu, Anda dapat menggunakan skrip berikut:
UPDATE STATISTICS <schema_name>.<table_name> <index_name>
Jika Anda ingin memperbarui statistik IX_Sales_OrderLines_Perf_20160301_02 indeks OrderLines tabel, Anda dapat menjalankan skrip berikut:
UPDATE STATISTICS [Sales].[OrderLines] [IX_Sales_OrderLines_Perf_20160301_02]
Anda juga dapat memperbarui statistik seluruh database. Jika Anda memiliki database yang sangat kecil dengan beberapa tabel dan jumlah data yang sedikit, maka Anda dapat memperbarui statistik semua tabel dalam database. Lihat skrip berikut:
USE wideworldimporters go EXEC Sp_updatestats
Memperbarui statistik untuk tabel dengan data yang sering dimasukkan / diperbarui / dihapus
Pada database besar, penjadwalan tugas statistik menjadi rumit, terutama bila Anda hanya memiliki beberapa jam untuk melakukan pemeliharaan indeks, memperbarui statistik, dan memenuhi tugas pemeliharaan lainnya. Yang saya maksud dengan database besar adalah database yang berisi ribuan tabel dan setiap tabel berisi ribuan baris. Misalnya, kami memiliki database bernama X. Ini memiliki ratusan tabel, dan setiap tabel memiliki jutaan baris. Dan hanya beberapa tabel yang sering diperbarui. Tabel lain jarang diubah dan sangat sedikit transaksi yang dilakukan pada tabel tersebut. Seperti yang saya sebutkan sebelumnya, untuk menjaga kinerja database tetap sesuai standar, statistik tabel harus diperbarui. Jadi kami membuat rencana pemeliharaan SQL untuk memperbarui statistik semua tabel dalam database X. Ketika SQL server memperbarui statistik tabel, itu menggunakan sejumlah besar sumber daya yang dapat menyebabkan masalah kinerja. Jadi, butuh waktu lama untuk memperbarui statistik dari ratusan tabel besar dan sementara statistik diperbarui, kinerja database berkurang secara signifikan. Dalam keadaan seperti itu, selalu disarankan untuk memperbarui statistik hanya untuk tabel yang sering diperbarui. Anda dapat melacak perubahan volume data atau jumlah baris dari waktu ke waktu dengan menggunakan tampilan pengelolaan dinamis berikut:1. sys.partitions memberikan informasi tentang jumlah baris dalam sebuah tabel. 2. sys.dm_db_partition_stats memberikan informasi tentang jumlah baris dan jumlah halaman, per partisi. 3. sys.dm_db_index_physical_stats memberikan informasi tentang jumlah baris dan halaman, ditambah informasi tentang fragmentasi indeks dan banyak lagi. Detail tentang volume data penting, tetapi tidak membuat gambaran aktivitas database menjadi lengkap. Misalnya, tabel staging yang memiliki jumlah record yang hampir sama dapat dihapus dari tabel atau disisipkan ke dalam tabel setiap hari. Karena itu, snapshot dari jumlah baris akan menunjukkan bahwa tabel itu statis. Ada kemungkinan bahwa catatan yang ditambahkan dan dihapus memiliki nilai yang sangat berbeda yang sangat mengubah distribusi data. Dalam hal ini, memperbarui statistik secara otomatis di SQL Server membuat statistik menjadi tidak berarti. Oleh karena itu, melacak jumlah modifikasi pada tabel sangat berguna. Ini dapat dilakukan dengan cara berikut:1. rowmodctr kolom di sys.sysindexes 2. modified_count kolom di sys.system_internals_partition_columns 3. modification_counter kolom di sys.dm_db_stats_properties Jadi, seperti yang saya jelaskan sebelumnya, jika Anda memiliki waktu terbatas untuk pemeliharaan database, selalu disarankan untuk memperbarui statistik hanya untuk tabel dengan frekuensi perubahan data yang lebih tinggi (masukkan / perbarui / hapus). Untuk melakukannya secara efisien, saya telah membuat skrip yang memperbarui statistik untuk tabel "aktif". Script melakukan tugas berikut:• Mendeklarasikan parameter yang diperlukan • Membuat tabel sementara bernama #tempstatistics untuk menyimpan nama tabel, nama skema, dan nama database • Membuat tabel lain bernama #tempdatabase untuk menyimpan nama database. Pertama, jalankan skrip berikut untuk membuat dua tabel:
DECLARE @databasename VARCHAR(500) DECLARE @i INT=0 DECLARE @DBCOunt INT DECLARE @SQLCOmmand NVARCHAR(max) DECLARE @StatsUpdateCOmmand NVARCHAR(max) CREATE TABLE #tempstatistics ( databasename VARCHAR(max), tablename VARCHAR(max), schemaname VARCHAR(max) ) CREATE TABLE #tempdatabases ( databasename VARCHAR(max) ) INSERT INTO #tempdatabases (databasename) SELECT NAME FROM sys.databases WHERE database_id > 4 ORDER BY NAME
Selanjutnya, tulis while loop untuk membuat kueri SQL dinamis yang mengulangi semua database dan menyisipkan daftar tabel yang memiliki penghitung modifikasi lebih besar dari 200 ke dalam #tempstatistics meja. Untuk mendapatkan informasi tentang perubahan data, saya menggunakan sys.dm_db_stats_properties . Pelajari contoh kode berikut:
SET @DBCOunt=(SELECT Count(*) FROM #tempdatabases) WHILE ( @i < @DBCOunt ) BEGIN DECLARE @DBName VARCHAR(max) SET @DBName=(SELECT TOP 1 databasename FROM #tempdatabases) SET @SQLCOmmand= ' use [' + @DBName + ']; select distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter FROM [' + @DBName+ '].sys.objects AS obj inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like ''sys%'')a' INSERT INTO #tempstatistics (databasename, tablename, schemaname) EXEC Sp_executesql @SQLCOmmand
Sekarang, buat loop kedua di dalam loop pertama. Ini akan menghasilkan Query SQL dinamis yang memperbarui statistik dengan pemindaian penuh. Lihat contoh kode di bawah ini:
DECLARE @j INT=0 DECLARE @StatCount INT SET @StatCount =(SELECT Count(*) FROM #tempstatistics) WHILE @J < @StatCount BEGIN DECLARE @DatabaseName_Stats VARCHAR(max) DECLARE @Table_Stats VARCHAR(max) DECLARE @Schema_Stats VARCHAR(max) DECLARE @StatUpdateCommand NVARCHAR(max) SET @DatabaseName_Stats=(SELECT TOP 1 databasename FROM #tempstatistics) SET @Table_Stats=(SELECT TOP 1 tablename FROM #tempstatistics) SET @Schema_Stats=(SELECT TOP 1 schemaname FROM #tempstatistics) SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats + '].[' + @Schema_Stats + '].[' + @Table_Stats + '] with fullscan' EXEC Sp_executesql @StatUpdateCommand SET @[email protected] + 1 DELETE FROM #tempstatistics WHERE databasename = @DatabaseName_Stats AND tablename = @Table_Stats AND schemaname = @Schema_Stats END SET @[email protected] + 1 DELETE FROM #tempdatabases WHERE databasename = @DBName END
Setelah eksekusi skrip selesai, semua tabel sementara akan dihapus.
SELECT * FROM #tempstatistics DROP TABLE #tempdatabases DROP TABLE #tempstatistics
Seluruh script akan muncul sebagai berikut:
--set count on CREATE PROCEDURE Statistics_maintenance AS BEGIN DECLARE @databasename VARCHAR(500) DECLARE @i INT=0 DECLARE @DBCOunt INT DECLARE @SQLCOmmand NVARCHAR(max) DECLARE @StatsUpdateCOmmand NVARCHAR(max) CREATE TABLE #tempstatistics ( databasename VARCHAR(max), tablename VARCHAR(max), schemaname VARCHAR(max) ) CREATE TABLE #tempdatabases ( databasename VARCHAR(max) ) INSERT INTO #tempdatabases (databasename) SELECT NAME FROM sys.databases WHERE database_id > 4 ORDER BY NAME SET @DBCOunt=(SELECT Count(*) FROM #tempdatabases) WHILE ( @i < @DBCOunt ) BEGIN DECLARE @DBName VARCHAR(max) SET @DBName=(SELECT TOP 1 databasename FROM #tempdatabases) SET @SQLCOmmand= ' use [' + @DBName + ']; select distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter FROM [' + @DBName+ '].sys.objects AS obj inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like ''sys%'')a' INSERT INTO #tempstatistics (databasename, tablename, schemaname) EXEC Sp_executesql @SQLCOmmand DECLARE @j INT=0 DECLARE @StatCount INT SET @StatCount =(SELECT Count(*) FROM #tempstatistics) WHILE @J < @StatCount BEGIN DECLARE @DatabaseName_Stats VARCHAR(max) DECLARE @Table_Stats VARCHAR(max) DECLARE @Schema_Stats VARCHAR(max) DECLARE @StatUpdateCommand NVARCHAR(max) SET @DatabaseName_Stats=(SELECT TOP 1 databasename FROM #tempstatistics) SET @Table_Stats=(SELECT TOP 1 tablename FROM #tempstatistics) SET @Schema_Stats=(SELECT TOP 1 schemaname FROM #tempstatistics) SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats + '].[' + @Schema_Stats + '].[' + @Table_Stats + '] with fullscan' EXEC Sp_executesql @StatUpdateCommand SET @[email protected] + 1 DELETE FROM #tempstatistics WHERE databasename = @DatabaseName_Stats AND tablename = @Table_Stats AND schemaname = @Schema_Stats END SET @[email protected] + 1 DELETE FROM #tempdatabases WHERE databasename = @DBName END SELECT * FROM #tempstatistics DROP TABLE #tempdatabases DROP TABLE #tempstatistics END
Anda juga dapat mengotomatiskan skrip ini dengan membuat pekerjaan Agen Server SQL yang akan mengeksekusinya pada waktu yang dijadwalkan. Petunjuk langkah demi langkah untuk mengotomatisasi pekerjaan ini diberikan di bawah ini.
Membuat Pekerjaan SQL
Pertama, mari buat SQL Job untuk mengotomatisasi proses. Untuk melakukannya, buka SSMS, sambungkan ke server yang diinginkan dan perluas SQL Server Agent, klik kanan pada Pekerjaan dan pilih Pekerjaan Baru . Di Pekerjaan Baru kotak dialog, ketik nama yang diinginkan di Nama bidang. Sekarang, klik Langkah opsi menu di panel kiri Pekerjaan Baru kotak dialog, lalu klik Baru dalam Langkah jendela. Dalam Langkah Pekerjaan Baru kotak dialog, yang terbuka, berikan nama yang diinginkan di Nama langkah bidang. Selanjutnya, pilih Skrip Transact-SQL (T-SQL) di Jenis kotak drop-down. Kemudian, pilih DBATools di Database kotak drop-down dan tulis kueri berikut di kotak teks perintah:
EXEC Statistics_maintenance
Untuk mengonfigurasi jadwal pekerjaan, klik Jadwal opsi menu di Pekerjaan Baru kotak dialog. Jadwal Kerja Baru kotak dialog terbuka. Di Nama bidang, berikan nama jadwal yang diinginkan. Dalam contoh kami, kami ingin pekerjaan ini dieksekusi setiap malam pada jam 1 pagi, oleh karena itu dalam Terjadi kotak tarik-turun di Frekuensi bagian, pilih Harian . Dalam Terjadi sekali pada bidang di Frekuensi harian bagian, masukkan 01:00:00. Klik Oke untuk menutup Jadwal Kerja Baru jendela lalu klik OK lagi di Pekerjaan Baru kotak dialog untuk menutupnya. Sekarang mari kita uji pekerjaan ini. Di bawah SQL Server Agent, klik kanan Update_Statistics_Daily . Jika pekerjaan telah berhasil dijalankan, Anda akan melihat jendela berikut.
Ringkasan
Dalam artikel ini, masalah berikut telah dibahas:1. Cara memperbarui statistik tabel menggunakan T-SQL Script. 2. Bagaimana memperoleh informasi tentang perubahan volume data dan frekuensi perubahan data. 3. Cara membuat skrip yang memperbarui statistik pada tabel yang aktif. 4. Cara membuat SQL Server Agent Job untuk mengeksekusi skrip pada waktu yang dijadwalkan.