sys.dm_db_index_physical_stats (T-SQL)
Berlaku untuk: SQL ServerAzure SQL Database Azure SQL Managed Instance
Mengembalikan informasi ukuran dan fragmentasi untuk data dan indeks tabel atau tampilan yang ditentukan di Mesin Database SQL Server. Untuk indeks, satu baris dikembalikan untuk setiap tingkat pohon B di setiap partisi. Untuk timbunan, satu baris dikembalikan untuk IN_ROW_DATA
unit alokasi setiap partisi. Untuk data objek besar (LOB), satu baris dikembalikan untuk LOB_DATA
unit alokasi setiap partisi. Jika data luapan baris ada dalam tabel, satu baris dikembalikan untuk ROW_OVERFLOW_DATA
unit alokasi di setiap partisi.
Catatan
Dokumentasi menggunakan istilah pohon B umumnya dalam referensi ke indeks. Dalam indeks rowstore, Mesin Database mengimplementasikan pohon B+. Ini tidak berlaku untuk indeks penyimpan kolom atau indeks pada tabel yang dioptimalkan memori. Untuk informasi selengkapnya, lihat panduan arsitektur dan desain indeks SQL Server dan Azure SQL.
sys.dm_db_index_physical_stats
tidak mengembalikan informasi tentang indeks yang dioptimalkan memori. Untuk informasi tentang penggunaan indeks yang dioptimalkan memori, lihat sys.dm_db_xtp_index_stats.
Jika Anda mengkueri sys.dm_db_index_physical_stats
instans server yang menghosting replika sekunder yang dapat dibaca grup ketersediaan, Anda mungkin mengalami REDO
masalah pemblokiran. Ini karena tampilan manajemen dinamis ini memperoleh kunci Intent-Shared (IS) pada tabel pengguna atau tampilan yang ditentukan yang dapat memblokir permintaan berdasarkan REDO
utas untuk kunci Eksklusif (X) pada tabel atau tampilan pengguna tersebut.
Sintaks
sys.dm_db_index_physical_stats (
{ database_id | NULL | 0 | DEFAULT }
, { object_id | NULL | 0 | DEFAULT }
, { index_id | NULL | 0 | -1 | DEFAULT }
, { partition_number | NULL | 0 | DEFAULT }
, { mode | NULL | DEFAULT }
)
Argumen
database_id | NULL | 0 | DEFAULT
ID database. database_id kecil. Input yang valid adalah ID database, , NULL
, 0
atau DEFAULT
. Default adalah 0
. NULL
, 0
, dan DEFAULT
merupakan nilai yang setara dalam konteks ini.
Tentukan NULL
untuk mengembalikan informasi untuk semua database dalam instans SQL Server. Jika Anda menentukan NULL
untuk database_id, Anda juga harus menentukan NULL
untuk object_id, index_id, dan partition_number.
Fungsi bawaan DB_ID dapat ditentukan. Saat Anda menggunakan DB_ID
tanpa menentukan nama database, tingkat kompatibilitas database saat ini harus 90
atau lebih besar.
object_id | NULL | 0 | DEFAULT
ID objek tabel atau tampilan indeks aktif. object_id adalah int. Input yang valid adalah ID tabel dan tampilan, NULL
, , 0
atau DEFAULT
. Default adalah 0
. NULL
, 0
, dan DEFAULT
merupakan nilai yang setara dalam konteks ini.
Di SQL Server 2016 (13.x) dan versi yang lebih baru, input yang valid juga menyertakan nama antrean broker layanan atau nama tabel internal antrean. Ketika parameter default diterapkan (yaitu, semua objek, semua indeks, dll.), informasi fragmentasi untuk semua antrean disertakan dalam tataan hasil.
Tentukan NULL
untuk mengembalikan informasi untuk semua tabel dan tampilan dalam database yang ditentukan. Jika Anda menentukan NULL
untuk object_id, Anda juga harus menentukan NULL
untuk index_id dan partition_number.
index_id | 0 | NULL | -1 | DEFAULT
ID indeks. index_id int. Input yang valid adalah ID indeks, 0
jika object_id adalah tumpukan, NULL
, -1
, atau DEFAULT
. Default adalah -1
. NULL
, -1
, dan DEFAULT
merupakan nilai yang setara dalam konteks ini.
Tentukan NULL
untuk mengembalikan informasi untuk semua indeks untuk tabel atau tampilan dasar. Jika Anda menentukan NULL
untuk index_id, Anda juga harus menentukan NULL
untuk partition_number.
partition_number | NULL | 0 | DEFAULT
Nomor partisi dalam objek. partition_number int. Input yang valid adalah partion_number indeks atau tumpukan, NULL
, , 0
atau DEFAULT
. Default adalah 0
. NULL
, 0
, dan DEFAULT
merupakan nilai yang setara dalam konteks ini.
Tentukan NULL
untuk mengembalikan informasi untuk semua partisi objek pemilik.
partition_number berbasis 1. Indeks atau tumpukan yang tidak dipartisi telah partition_number diatur ke 1
.
mode | NULL | DEFAULT
Nama mode. mode menentukan tingkat pemindaian yang digunakan untuk mendapatkan statistik. mode adalah sysname. Input yang valid adalah DEFAULT
, , LIMITED
NULL
, SAMPLED
, atau DETAILED
. Defaultnya (NULL
) adalah LIMITED
.
Tabel dikembalikan
Nama kolom | Jenis data | Deskripsi |
---|---|---|
database_id |
smallint | ID database tabel atau tampilan. Di Azure SQL Database, nilainya unik dalam satu database atau kumpulan elastis, tetapi tidak dalam server logis. |
object_id |
int | ID objek tabel atau tampilan tempat indeks berada. |
index_id |
int | ID indeks indeks.0 = Timbunan. |
partition_number |
int | Nomor partisi berbasis 1 dalam objek pemilik; tabel, tampilan, atau indeks.1 = Indeks atau tumpukan yang tidak dipartisi. |
index_type_desc |
nvarchar(60) | Deskripsi jenis indeks: - HEAP - CLUSTERED INDEX - NONCLUSTERED INDEX - PRIMARY XML INDEX - EXTENDED INDEX - XML INDEX - COLUMNSTORE MAPPING INDEX (internal)- COLUMNSTORE DELETEBUFFER INDEX (internal)- COLUMNSTORE DELETEBITMAP INDEX (internal) |
alloc_unit_type_desc |
nvarchar(60) | Deskripsi jenis unit alokasi: - IN_ROW_DATA - LOB_DATA - ROW_OVERFLOW_DATA Unit LOB_DATA alokasi berisi data yang disimpan dalam kolom jenis teks, ntext, gambar, varchar(max), nvarchar(max), varbinary(max), dan xml. Untuk informasi selengkapnya, lihat Jenis Data.Unit ROW_OVERFLOW_DATA alokasi berisi data yang disimpan dalam kolom jenis varchar(n), nvarchar(n), varbinary(n), dan sql_variant yang didorong dari baris. |
index_depth |
kecil | Jumlah tingkat indeks.1 = Timbunan, atau LOB_DATA unit ROW_OVERFLOW_DATA alokasi. |
index_level |
kecil | Tingkat indeks saat ini.0 untuk tingkat daun indeks, timbunan, dan LOB_DATA atau ROW_OVERFLOW_DATA unit alokasi.Lebih besar dari 0 untuk tingkat indeks nonleaf. index_level adalah yang tertinggi pada tingkat akar indeks.Tingkat indeks nonleaf hanya diproses ketika mode adalah DETAILED . |
avg_fragmentation_in_percent |
float | Fragmentasi logis untuk indeks, atau fragmentasi tingkat untuk timbunan di IN_ROW_DATA unit alokasi.Nilai diukur sebagai persentase dan memperhitungkan beberapa file. Untuk definisi fragmentasi logis dan luas, lihat Komentar. 0 untuk LOB_DATA unit alokasi dan ROW_OVERFLOW_DATA . NULL untuk timbunan ketika mode adalah SAMPLED . |
fragment_count |
bigint | Jumlah fragmen dalam tingkat daun unit alokasi IN_ROW_DATA . Untuk informasi selengkapnya tentang fragmen, lihat Komentar.NULL untuk tingkat nonleaf indeks, dan LOB_DATA atau ROW_OVERFLOW_DATA unit alokasi. NULL untuk timbunan ketika mode adalah SAMPLED . |
avg_fragment_size_in_pages |
float | Jumlah rata-rata halaman dalam satu fragmen dalam tingkat daun unit alokasi IN_ROW_DATA .NULL untuk tingkat nonleaf indeks, dan LOB_DATA atau ROW_OVERFLOW_DATA unit alokasi. NULL untuk timbunan ketika mode adalah SAMPLED . |
page_count |
bigint | Jumlah total halaman indeks atau data. Untuk indeks, jumlah total halaman indeks di tingkat pohon B saat ini di IN_ROW_DATA unit alokasi.Untuk timbunan, jumlah total halaman data di IN_ROW_DATA unit alokasi.Untuk LOB_DATA unit alokasi atau ROW_OVERFLOW_DATA , jumlah total halaman di unit alokasi. |
avg_page_space_used_in_percent |
float | Persentase rata-rata ruang penyimpanan data yang tersedia yang digunakan di semua halaman. Untuk indeks, rata-rata berlaku untuk tingkat pohon B saat ini di IN_ROW_DATA unit alokasi.Untuk timbunan, rata-rata semua halaman data di IN_ROW_DATA unit alokasi.Untuk LOB_DATA unit alokasi atau ROW_OVERFLOW_DATA , rata-rata semua halaman di unit alokasi. NULL ketika mode adalah LIMITED . |
record_count |
bigint | Jumlah total rekaman. Untuk indeks, jumlah total rekaman berlaku untuk tingkat pohon B saat ini di IN_ROW_DATA unit alokasi.Untuk timbunan, jumlah total rekaman di IN_ROW_DATA unit alokasi.Catatan: Untuk timbunan, jumlah rekaman yang dikembalikan dari fungsi ini mungkin tidak cocok dengan jumlah baris yang dikembalikan dengan menjalankan SELECT COUNT(*) terhadap timbunan. Ini karena baris dapat berisi beberapa rekaman. Misalnya, dalam beberapa situasi pembaruan, satu baris timbunan mungkin memiliki catatan penerusan dan rekaman yang diteruskan sebagai hasil dari operasi pembaruan. Selain itu, sebagian besar baris LOB besar dibagi menjadi beberapa rekaman dalam LOB_DATA penyimpanan.Untuk LOB_DATA unit alokasi atau ROW_OVERFLOW_DATA , jumlah total rekaman di unit alokasi lengkap. NULL ketika mode adalah LIMITED . |
ghost_record_count |
bigint | Jumlah catatan hantu yang siap dihapus oleh tugas pembersihan hantu di unit alokasi.0 untuk tingkat nonleaf indeks di IN_ROW_DATA unit alokasi. NULL ketika mode adalah LIMITED . |
version_ghost_record_count |
bigint | Jumlah catatan hantu yang dipertahankan oleh transaksi isolasi rekam jepret yang luar biasa di unit alokasi.0 untuk tingkat nonleaf indeks di IN_ROW_DATA unit alokasi. NULL ketika mode adalah LIMITED . |
min_record_size_in_bytes |
int | Ukuran rekaman minimum dalam byte. Untuk indeks, ukuran rekaman minimum berlaku untuk tingkat pohon B saat ini di IN_ROW_DATA unit alokasi.Untuk timbunan, ukuran rekaman minimum dalam IN_ROW_DATA unit alokasi.Untuk LOB_DATA unit alokasi atau ROW_OVERFLOW_DATA , ukuran rekaman minimum di unit alokasi lengkap. NULL ketika mode adalah LIMITED . |
max_record_size_in_bytes |
int | Ukuran rekaman maksimum dalam byte. Untuk indeks, ukuran rekaman maksimum berlaku untuk tingkat pohon B saat ini di IN_ROW_DATA unit alokasi.Untuk timbunan, ukuran rekaman maksimum dalam IN_ROW_DATA unit alokasi.Untuk LOB_DATA unit alokasi atau ROW_OVERFLOW_DATA , ukuran rekaman maksimum di unit alokasi lengkap. NULL ketika mode adalah LIMITED . |
avg_record_size_in_bytes |
float | Ukuran rekaman rata-rata dalam byte. Untuk indeks, ukuran rekaman rata-rata berlaku untuk tingkat pohon B saat ini di IN_ROW_DATA unit alokasi.Untuk timbunan, ukuran rekaman rata-rata dalam IN_ROW_DATA unit alokasi.Untuk LOB_DATA unit alokasi atau ROW_OVERFLOW_DATA , ukuran rekaman rata-rata dalam unit alokasi lengkap. NULL ketika mode adalah LIMITED . |
forwarded_record_count |
bigint | Jumlah rekaman dalam timbunan yang memiliki penunjuk maju ke lokasi data lain. (Status ini terjadi selama pembaruan, ketika tidak ada cukup ruang untuk menyimpan baris baru di lokasi asli.)NULL untuk unit alokasi apa pun selain IN_ROW_DATA unit alokasi untuk timbunan. NULL untuk timbunan ketika mode adalah LIMITED . |
compressed_page_count |
bigint | Jumlah halaman terkompresi. Untuk timbunan, halaman yang baru dialokasikan tidak PAGE dikompresi. Timbunan dikompresi PAGE dalam dua kondisi khusus: ketika data diimpor secara massal atau ketika timbunan dibangun kembali. Operasi DML umum yang menyebabkan alokasi halaman tidak PAGE dikompresi. Bangun kembali tumpukan ketika compressed_page_count nilai tumbuh lebih besar dari ambang yang Anda inginkan.Untuk tabel yang memiliki indeks berkluster, compressed_page_count nilai menunjukkan efektivitas pemadatan PAGE . |
hobt_id |
bigint | ID tumpukan atau pohon B dari indeks atau partisi. Untuk indeks penyimpan kolom, ini adalah ID untuk set baris yang melacak data penyimpan kolom internal untuk partisi. Kumpulan baris disimpan sebagai tumpukan data atau pohon B. Mereka memiliki ID indeks yang sama dengan indeks penyimpan kolom induk. Untuk informasi selengkapnya, lihat sys.internal_partitions. |
columnstore_delete_buffer_state |
kecil | 0 = NOT_APPLICABLE 1 = OPEN 2 = DRAINING 3 = FLUSHING 4 = RETIRING 5 = READY Berlaku untuk: SQL Server 2016 (13.x) dan versi yang lebih baru, Azure SQL Database, dan Azure SQL Managed Instance |
columnstore_delete_buffer_state_desc |
nvarchar(60) | NOT VALID - indeks induk bukan indeks penyimpan kolom.OPEN - deleter dan pemindai menggunakan ini.DRAINING - deleter menguras keluar tetapi pemindai masih menggunakannya.FLUSHING - buffer ditutup dan baris dalam buffer sedang ditulis ke bitmap penghapusan.RETIRING - baris dalam buffer penghapusan tertutup ditulis ke bitmap penghapusan, tetapi buffer belum dipotong karena pemindai masih menggunakannya. Pemindai baru tidak perlu menggunakan buffer yang dihentikan karena buffer terbuka sudah cukup.READY - Buffer penghapusan ini siap digunakan.Berlaku untuk: SQL Server 2016 (13.x) dan versi yang lebih baru, Azure SQL Database, dan Azure SQL Managed Instance |
version_record_count |
bigint | Ini adalah jumlah rekaman versi baris yang dipertahankan dalam indeks ini. Versi baris ini dikelola oleh fitur pemulihan database yang dipercepat. Berlaku untuk: SQL Server 2019 (15.x) dan versi yang lebih baru, dan Azure SQL Database |
inrow_version_record_count |
bigint | Jumlah rekaman versi ADR yang disimpan di baris data untuk pengambilan cepat. Berlaku untuk: SQL Server 2019 (15.x) dan versi yang lebih baru, dan Azure SQL Database |
inrow_diff_version_record_count |
bigint | Jumlah rekaman versi ADR yang disimpan dalam bentuk perbedaan dari versi dasar. Berlaku untuk: SQL Server 2019 (15.x) dan versi yang lebih baru, dan Azure SQL Database |
total_inrow_version_payload_size_in_bytes |
bigint | Ukuran total dalam byte rekaman versi dalam baris untuk indeks ini. Berlaku untuk: SQL Server 2019 (15.x) dan versi yang lebih baru, dan Azure SQL Database |
offrow_regular_version_record_count |
bigint | Jumlah rekaman versi yang disimpan di luar baris data asli. Berlaku untuk: SQL Server 2019 (15.x) dan versi yang lebih baru, dan Azure SQL Database |
offrow_long_term_version_record_count |
bigint | Jumlah rekaman versi yang dianggap jangka panjang. Berlaku untuk: SQL Server 2019 (15.x) dan versi yang lebih baru, dan Azure SQL Database |
Catatan
Dokumentasi menggunakan istilah pohon B umumnya dalam referensi ke indeks. Dalam indeks rowstore, Mesin Database mengimplementasikan pohon B+. Ini tidak berlaku untuk indeks penyimpan kolom atau indeks pada tabel yang dioptimalkan memori. Untuk informasi selengkapnya, lihat panduan arsitektur dan desain indeks SQL Server dan Azure SQL.
Keterangan
Fungsi sys.dm_db_index_physical_stats
manajemen dinamis menggantikan DBCC SHOWCONTIG
pernyataan.
Mode pemindaian
Mode di mana fungsi dijalankan menentukan tingkat pemindaian yang dilakukan untuk mendapatkan data statistik yang digunakan oleh fungsi. mode ditentukan sebagai LIMITED
, , SAMPLED
atau DETAILED
. Fungsi ini melintasi rantai halaman untuk unit alokasi yang membentuk partisi tabel atau indeks yang ditentukan. sys.dm_db_index_physical_stats
hanya memerlukan kunci tabel Intent-Shared (IS), terlepas dari mode yang dijalankannya.
LIMITED
Mode ini adalah mode tercepat dan memindai jumlah halaman terkecil. Untuk indeks, hanya halaman tingkat induk pohon B (yaitu, halaman di atas tingkat daun) yang dipindai. Untuk tumpukan, halaman PFS dan IAM terkait diperiksa dan halaman data tumpukan dipindai dalam LIMITED
mode.
Dengan LIMITED
mode, compressed_page_count
adalah NULL
karena Mesin Database hanya memindai halaman nonleaf dari pohon B dan halaman IAM dan PFS dari tumpukan. Gunakan SAMPLED
mode untuk mendapatkan perkiraan nilai untuk compressed_page_count
, dan gunakan DETAILED
mode untuk mendapatkan nilai aktual untuk compressed_page_count
. Mode mengembalikan SAMPLED
statistik berdasarkan sampel 1 persen dari semua halaman dalam indeks atau timbunan. Hasil dalam SAMPLED
mode harus dianggap sebagai perkiraan. Jika indeks atau timbunan memiliki kurang dari 10.000 halaman, DETAILED
mode digunakan alih-alih SAMPLED
.
Mode DETAILED
memindai semua halaman dan mengembalikan semua statistik.
Mode semakin lambat dari LIMITED
ke DETAILED
, karena lebih banyak pekerjaan dilakukan di setiap mode. Untuk mengukur ukuran atau tingkat fragmentasi tabel atau indeks dengan cepat, gunakan LIMITED
mode . Ini adalah yang tercepat dan tidak mengembalikan baris untuk setiap tingkat nonleaf di IN_ROW_DATA
unit alokasi indeks.
Menggunakan fungsi sistem untuk menentukan nilai parameter
Anda dapat menggunakan fungsi Transact-SQL DB_ID dan OBJECT_ID untuk menentukan nilai untuk parameter database_id dan object_id . Namun, meneruskan nilai yang tidak valid untuk fungsi-fungsi ini dapat menyebabkan hasil yang tidak diinginkan. Misalnya, jika database atau nama objek tidak dapat ditemukan karena tidak ada atau salah dieja, kedua fungsi mengembalikan NULL
. Fungsi ini sys.dm_db_index_physical_stats
menafsirkan NULL
sebagai nilai kartubebas yang menentukan semua database atau semua objek.
Selain itu, fungsi diproses OBJECT_ID
sebelum sys.dm_db_index_physical_stats
fungsi dipanggil dan oleh karena itu dievaluasi dalam konteks database saat ini, bukan database yang ditentukan dalam database_id. Perilaku ini dapat menyebabkan OBJECT_ID
fungsi mengembalikan NULL
nilai; atau, jika nama objek ada dalam konteks database saat ini dan database yang ditentukan, pesan kesalahan dikembalikan. Contoh berikut menunjukkan hasil yang tidak diinginkan ini.
USE master;
GO
-- In this example, OBJECT_ID is evaluated in the context of the master database.
-- Because Person.Address does not exist in master, the function returns NULL.
-- When NULL is specified as an object_id, all objects in the database are returned.
-- The same results are returned when an object that is not valid is specified.
SELECT * FROM sys.dm_db_index_physical_stats
(DB_ID(N'AdventureWorks2022'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- This example demonstrates the results of specifying a valid object name
-- that exists in both the current database context and
-- in the database specified in the database_id parameter of the
-- sys.dm_db_index_physical_stats function.
-- An error is returned because the ID value returned by OBJECT_ID does not
-- match the ID value of the object in the specified database.
CREATE DATABASE Test;
GO
USE Test;
GO
CREATE SCHEMA Person;
GO
CREATE Table Person.Address(c1 int);
GO
USE AdventureWorks2022;
GO
SELECT * FROM sys.dm_db_index_physical_stats
(DB_ID(N'Test'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- Clean up temporary database.
DROP DATABASE Test;
GO
Praktik terbaik
Selalu pastikan bahwa ID yang valid dikembalikan saat Anda menggunakan DB_ID
atau OBJECT_ID
. Misalnya, saat Anda menggunakan OBJECT_ID
, tentukan nama tiga bagian seperti OBJECT_ID(N'AdventureWorks2022.Person.Address')
, atau uji nilai yang dikembalikan oleh fungsi sebelum Anda menggunakannya dalam sys.dm_db_index_physical_stats
fungsi . Contoh A dan B yang mengikuti menunjukkan cara yang aman untuk menentukan ID database dan objek.
Mendeteksi fragmentasi
Fragmentasi terjadi melalui proses modifikasi data (INSERT
, UPDATE
, dan DELETE
pernyataan) yang dibuat terhadap tabel dan, oleh karena itu, ke indeks yang ditentukan pada tabel. Karena modifikasi ini biasanya tidak didistribusikan secara merata di antara baris tabel dan indeks, kepenuhan setiap halaman dapat bervariasi dari waktu ke waktu. Untuk kueri yang memindai bagian atau semua indeks tabel, fragmentasi semacam ini dapat menyebabkan lebih banyak pembacaan halaman, yang menghambat pemindaian data paralel.
Tingkat fragmentasi indeks atau tumpukan ditampilkan di avg_fragmentation_in_percent
kolom. Untuk tumpukan, nilai mewakili fragmentasi luas dari tumpukan. Untuk indeks, nilai mewakili fragmentasi logis indeks. Tidak seperti DBCC SHOWCONTIG
, algoritma perhitungan fragmentasi dalam kedua kasus mempertimbangkan penyimpanan yang mencakup beberapa file dan, oleh karena itu, akurat.
Fragmentasi logis
Ini adalah persentase halaman di luar urutan di halaman daun indeks. Halaman di luar urutan adalah halaman di mana halaman fisik berikutnya yang dialokasikan ke indeks bukan halaman yang diarahkan oleh penunjuk halaman berikutnya di halaman daun saat ini.
Fragmentasi tingkat
Ini adalah persentase tingkat di luar urutan di halaman daun tumpuk. Tingkat di luar urutan adalah tingkat yang berisi halaman saat ini untuk timbunan tidak secara fisik tingkat berikutnya setelah sejauh yang berisi halaman sebelumnya.
Nilai untuk avg_fragmentation_in_percent
harus sedekat mungkin dengan nol untuk performa maksimum. Namun, nilai dari 0 persen hingga 10 persen dapat diterima. Semua metode pengurangan fragmentasi, seperti membangun kembali, mengatur ulang, atau membuat ulang, dapat digunakan untuk mengurangi nilai-nilai ini. Untuk informasi selengkapnya tentang cara menganalisis tingkat fragmentasi dalam indeks, lihat Mengoptimalkan pemeliharaan indeks untuk meningkatkan performa kueri dan mengurangi konsumsi sumber daya.
Mengurangi fragmentasi dalam indeks
Saat indeks terfragmentasi dengan cara fragmentasi memengaruhi performa kueri, ada tiga pilihan untuk mengurangi fragmentasi:
Hilangkan dan buat ulang indeks berkluster.
Membuat ulang indeks berkluster mendistribusikan ulang data dan menghasilkan halaman data lengkap. Tingkat kepenuhan dapat dikonfigurasi dengan menggunakan
FILLFACTOR
opsi diCREATE INDEX
. Kelemahan dalam metode ini adalah bahwa indeks offline selama siklus drop dan pembuatan ulang, dan bahwa operasinya adalah atomik. Jika pembuatan indeks terganggu, indeks tidak dibuat ulang. Untuk informasi selengkapnya, lihat MEMBUAT INDEKS.Gunakan
ALTER INDEX REORGANIZE
, penggantian untuk , untukDBCC INDEXDEFRAG
menyusun ulang halaman tingkat daun indeks dalam urutan logis. Karena ini adalah operasi online, indeks tersedia saat pernyataan sedang berjalan. Operasi juga dapat terganggu tanpa kehilangan pekerjaan yang sudah selesai. Kelemahan dalam metode ini adalah tidak melakukan pekerjaan yang baik untuk mengatur ulang data sebagai operasi pembangunan ulang indeks, dan tidak memperbarui statistik.Gunakan
ALTER INDEX REBUILD
, pengganti untuk , untukDBCC DBREINDEX
membangun kembali indeks online atau offline. Untuk informasi selengkapnya, lihat ALTER INDEX (T-SQL).
Fragmentasi saja bukan alasan yang memadai untuk mengatur ulang atau membangun ulang indeks. Efek utama fragmentasi adalah memperlambat throughput read-ahead halaman selama pemindaian indeks. Ini menyebabkan waktu respons yang lebih lambat. Jika beban kerja kueri pada tabel atau indeks terfragmentasi tidak melibatkan pemindaian, karena beban kerja terutama pencarian singleton, menghapus fragmentasi tidak akan berpengaruh.
Catatan
Menjalankan DBCC SHRINKFILE
atau DBCC SHRINKDATABASE
dapat memperkenalkan fragmentasi jika indeks sebagian atau sepenuhnya dipindahkan selama operasi penyusutan. Oleh karena itu, jika operasi penyusutan harus dilakukan, Anda harus melakukannya sebelum fragmentasi dihapus.
Mengurangi fragmentasi dalam tumpukan
Untuk mengurangi fragmentasi tingkat timbunan, buat indeks berkluster pada tabel lalu jatuhkan indeks. Ini mendistribusikan ulang data saat indeks berkluster dibuat. Ini juga membuatnya optimal mungkin, mengingat distribusi ruang kosong yang tersedia dalam database. Ketika indeks berkluster kemudian dihilangkan untuk membuat ulang tumpukan, data tidak dipindahkan dan tetap optimal dalam posisi. Untuk informasi tentang cara melakukan operasi ini, lihat MEMBUAT INDEKS dan MENGHILANGKAN INDEKS.
Perhatian
Membuat dan menghilangkan indeks berkluster pada tabel, membangun kembali semua indeks non-kluster pada tabel tersebut dua kali.
Padatkan data objek besar
Secara default, pernyataan memampatkan ALTER INDEX REORGANIZE
halaman yang berisi data objek besar (LOB). Karena halaman LOB tidak dibatalkan alokasinya saat kosong, memadamkan data ini dapat meningkatkan penggunaan ruang disk jika banyak data LOB dihapus, atau kolom LOB dihilangkan.
Mengatur ulang indeks berkluster tertentu memampatkan semua kolom LOB yang terkandung dalam indeks berkluster. Mengatur ulang indeks nonclustered memadatkan semua kolom LOB yang merupakan kolom non-kunci (disertakan) dalam indeks. Ketika ALL
ditentukan dalam pernyataan, semua indeks yang terkait dengan tabel atau tampilan yang ditentukan diatur ulang. Selain itu, semua kolom LOB yang terkait dengan indeks terkluster, tabel yang mendasar, atau indeks non-kluster dengan kolom yang disertakan, dipadatkan.
Mengevaluasi penggunaan ruang disk
Kolom avg_page_space_used_in_percent
menunjukkan kepenuhan halaman. Untuk mencapai penggunaan ruang disk yang optimal, nilai ini harus mendekati 100 persen untuk indeks yang tidak memiliki banyak sisipan acak. Namun, indeks yang memiliki banyak sisipan acak dan memiliki halaman yang sangat penuh memiliki peningkatan jumlah pemisahan halaman. Ini menyebabkan lebih banyak fragmentasi. Oleh karena itu, untuk mengurangi pemisahan halaman, nilainya harus kurang dari 100 persen. Membangun ulang indeks dengan opsi yang ditentukan memungkinkan kepenuhan halaman diubah agar sesuai dengan FILLFACTOR
pola kueri pada indeks. Untuk informasi selengkapnya tentang faktor pengisian, lihat Menentukan Faktor Pengisian untuk Indeks. Selain itu, ALTER INDEX REORGANIZE
akan mempadatkan indeks dengan mencoba mengisi halaman ke FILLFACTOR
yang terakhir ditentukan. Ini meningkatkan nilai dalam avg_space_used_in_percent. ALTER INDEX REORGANIZE
tidak dapat mengurangi kepenuhan halaman. Sebagai gantinya, pembangunan ulang indeks harus dilakukan.
Mengevaluasi fragmen indeks
Fragmen terdiri dari halaman daun berturut-turut secara fisik dalam file yang sama untuk unit alokasi. Indeks memiliki setidaknya satu fragmen. Fragmen maksimum yang dapat dimiliki indeks sama dengan jumlah halaman dalam tingkat daun indeks. Fragmen yang lebih besar berarti bahwa I/O disk yang lebih sedikit diperlukan untuk membaca jumlah halaman yang sama. Oleh karena itu, semakin besar nilainya avg_fragment_size_in_pages
, semakin baik performa pemindaian rentang. Nilai avg_fragment_size_in_pages
dan avg_fragmentation_in_percent
berbanding terbalik satu sama lain. Oleh karena itu, membangun kembali atau mengatur ulang indeks harus mengurangi jumlah fragmentasi dan meningkatkan ukuran fragmen.
Batasan
Tidak mengembalikan data untuk indeks penyimpan kolom berkluster.
Izin
Memerlukan izin berikut:
CONTROL
izin pada objek yang ditentukan dalam database.VIEW DATABASE STATE
atauVIEW DATABASE PERFORMANCE STATE
(SQL Server 2022) izin untuk mengembalikan informasi tentang semua objek dalam database yang ditentukan, dengan menggunakan wildcard objek @object_id =NULL
.VIEW SERVER STATE
atauVIEW SERVER PERFORMANCE STATE
(SQL Server 2022) izin untuk mengembalikan informasi tentang semua database, dengan menggunakan kartubebas database @database_id =NULL
.
Pemberian VIEW DATABASE STATE
izin memungkinkan semua objek dalam database dikembalikan, terlepas dari izin apa pun CONTROL
yang ditolak pada objek tertentu.
Menolak VIEW DATABASE STATE
melarang semua objek dalam database untuk dikembalikan, terlepas dari izin apa pun CONTROL
yang diberikan pada objek tertentu. Selain itu, ketika kartubebas database @database_id = NULL
ditentukan, database dihilangkan.
Untuk informasi selengkapnya, lihat Tampilan manajemen dinamis sistem.
Contoh
Sampel kode Transact-SQL dalam artikel ini menggunakan AdventureWorks2022
database sampel atau AdventureWorksDW2022
, yang dapat Anda unduh dari halaman beranda Sampel Microsoft SQL Server dan Proyek Komunitas.
J. Mengembalikan informasi tentang tabel tertentu
Contoh berikut mengembalikan statistik ukuran dan fragmentasi untuk semua indeks dan partisi Person.Address
tabel. Mode pemindaian diatur ke LIMITED
untuk performa terbaik dan untuk membatasi statistik yang dikembalikan. Menjalankan kueri ini memerlukan, minimal, CONTROL
izin pada Person.Address
tabel.
DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.Person.Address');
IF @db_id IS NULL
BEGIN;
PRINT N'Invalid database';
END;
ELSE IF @object_id IS NULL
BEGIN;
PRINT N'Invalid object';
END;
ELSE
BEGIN;
SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , 'LIMITED');
END;
GO
B. Mengembalikan informasi tentang timbunan
Contoh berikut mengembalikan semua statistik untuk timbunan dbo.DatabaseLog
AdventureWorks2022
dalam database. Karena tabel berisi data LOB, baris dikembalikan untuk LOB_DATA
unit alokasi selain baris yang dikembalikan untuk IN_ROW_ALLOCATION_UNIT
yang menyimpan halaman data timbunan. Menjalankan kueri ini memerlukan, minimal, CONTROL
izin pada dbo.DatabaseLog
tabel.
DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.dbo.DatabaseLog');
IF @object_id IS NULL
BEGIN;
PRINT N'Invalid object';
END;
ELSE
BEGIN;
SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, 0, NULL , 'DETAILED');
END;
GO
C. Mengembalikan informasi untuk semua database
Contoh berikut mengembalikan semua statistik untuk semua tabel dan indeks dalam instans SQL Server dengan menentukan wildcard NULL
untuk semua parameter. Menjalankan kueri ini memerlukan VIEW SERVER STATE
izin.
SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);
GO
D. Menggunakan sys.dm_db_index_physical_stats dalam skrip untuk membangun kembali atau mengatur ulang indeks
Contoh berikut secara otomatis mengatur ulang atau membangun ulang semua partisi dalam database yang memiliki fragmentasi rata-rata lebih dari 10 persen. Menjalankan kueri ini memerlukan VIEW DATABASE STATE
izin. Contoh ini menentukan DB_ID
sebagai parameter pertama tanpa menentukan nama database.
-- Ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;
DECLARE @objectid INT;
DECLARE @indexid INT;
DECLARE @partitioncount BIGINT;
DECLARE @schemaname NVARCHAR(130);
DECLARE @objectname NVARCHAR(130);
DECLARE @indexname NVARCHAR(130);
DECLARE @partitionnum BIGINT;
DECLARE @partitions BIGINT;
DECLARE @frag FLOAT;
DECLARE @command NVARCHAR(4000);
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT object_id AS objectid,
index_id AS indexid,
partition_number AS partitionnum,
avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0
AND index_id > 0;
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR
FOR
SELECT *
FROM #work_to_do;
-- Open the cursor.
OPEN partitions;
-- Loop through the partitions.
WHILE (1 = 1)
BEGIN;
FETCH NEXT
FROM partitions
INTO @objectid,
@indexid,
@partitionnum,
@frag;
IF @@FETCH_STATUS < 0
BREAK;
SELECT @objectname = QUOTENAME(o.name),
@schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
INNER JOIN sys.schemas AS s
ON s.schema_id = o.schema_id
WHERE o.object_id = @objectid;
SELECT @indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = @objectid
AND index_id = @indexid;
SELECT @partitioncount = count(*)
FROM sys.partitions
WHERE object_id = @objectid
AND index_id = @indexid;
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
IF @frag < 30.0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
IF @frag >= 30.0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
IF @partitioncount > 1
SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS NVARCHAR(10));
EXEC (@command);
PRINT N'Executed: ' + @command;
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
-- Drop the temporary table.
DROP TABLE #work_to_do;
GO
E. Gunakan sys.dm_db_index_physical_stats untuk memperlihatkan jumlah halaman yang dikompresi halaman
Contoh berikut menunjukkan cara menampilkan dan membandingkan jumlah total halaman dengan halaman yang dikompresi baris dan halaman. Informasi ini dapat digunakan untuk menentukan manfaat yang disediakan kompresi untuk indeks atau tabel.
SELECT o.name,
ips.partition_number,
ips.index_type_desc,
ips.record_count,
ips.avg_record_size_in_bytes,
ips.min_record_size_in_bytes,
ips.max_record_size_in_bytes,
ips.page_count,
ips.compressed_page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
INNER JOIN sys.objects o
ON o.object_id = ips.object_id
ORDER BY record_count DESC;
F. Menggunakan sys.dm_db_index_physical_stats dalam mode SAMPLED
Contoh berikut menunjukkan bagaimana SAMPLED
mode mengembalikan perkiraan yang berbeda dari hasil DETAILED
mode.
CREATE TABLE t3 (
col1 INT PRIMARY KEY,
col2 VARCHAR(500)
)
WITH (DATA_COMPRESSION = PAGE);
GO
BEGIN TRANSACTION
DECLARE @idx INT = 0;
WHILE @idx < 1000000
BEGIN
INSERT INTO t3 (col1, col2)
VALUES (
@idx,
REPLICATE('a', 100) + CAST(@idx AS VARCHAR(10)) + REPLICATE('a', 380)
)
SET @idx = @idx + 1
END
COMMIT;
GO
SELECT page_count,
compressed_page_count,
forwarded_record_count,
*
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'SAMPLED');
SELECT page_count,
compressed_page_count,
forwarded_record_count,
*
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'DETAILED');
G. Antrean broker layanan kueri untuk fragmentasi indeks
Berlaku untuk: SQL Server 2016 (13.x) dan versi yang lebih baru
Contoh berikut menunjukkan cara mengkueri antrean broker server untuk fragmentasi.
--Using queue internal table name
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('sys.queue_messages_549576996'), DEFAULT, DEFAULT, DEFAULT);
--Using queue name directly
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('ExpenseQueue'), DEFAULT, DEFAULT, DEFAULT);