Mengapa basis data saya masih terfragmentasi setelah saya membangun kembali dan mengindeks ulang semuanya?

41

Saya memiliki database yang saya coba defragmentasi semua tabel sekaligus dengan menjalankan T-SQL ini:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

Dan kemudian menyalin dan menempelkan output ke jendela permintaan baru dan menjalankannya. Saya tidak mendapatkan kesalahan, tetapi saya masih memiliki fragmentasi. Saya mencoba menjalankan kedua perintah secara terpisah juga dan masih memiliki fragmentasi. Catatan: Saya telah dibuat sadar bahwa REORGANIZEitu tidak perlu oleh Aaron, dan saya sadar saya bisa menggunakan sql dinamis untuk mengotomatisasi ini.

Saya menjalankan ini untuk menentukan saya masih memiliki fragmentasi:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

Dan saya mendapat:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

Saya tahu saya kehilangan sesuatu yang sangat mendasar, tetapi saya tidak tahu apa.

Justin Dearing
sumber
Kesalahan apa yang Anda dapatkan? Juga adakah alasan Anda memilikinya mengatur ulang dan membangun kembali hal yang sama?
Shawn Melton
Shawn, saya minta maaf karena saya kehilangan satu kata. Saya tidak mendapatkan kesalahan. Mengenai mengapa saya menjalankan kedua perintah, saya melakukan itu setelah mencoba setiap perintah secara terpisah. Saya memperbarui pertanyaan saya.
Justin Dearing

Jawaban:

38

Meja kecil. Jumlah halaman dalam tabel Anda adalah:

11, 8, 6, 5, 13, 8, 10

Mereka menempati total 480kb. Secara harfiah tidak ada yang bisa defrag.

Sunting: Ini membutuhkan sedikit penjelasan.

Tabel atau indeks baru biasanya dialokasikan 8 halaman pertama dari tingkat campuran, bukan seragam. Jadi, dimungkinkan untuk masing-masing dari 8 halaman pertama dialokasikan dari berbagai campuran. Tabel atau indeks yang memakan 8 halaman karenanya dapat memiliki 8 fragmen, 1 pada masing-masing 8 luasan campuran yang berbeda.

Skrip defrag yang lebih banyak digunakan (beberapa contoh yang ditautkan di bawah) cenderung mengecualikan tabel kecil karena ini. IIRC, <500 halaman ada di salah satu atau keduanya. Pada ukuran ini, ada sedikit manfaat untuk defragmenting dan angka fragmentasi berpotensi miring oleh alokasi tingkat campuran.

Mark Storey-Smith
sumber
Ok, itu memuaskan kecuali orang lain memiliki jawaban yang lebih baik, saya akan menandai jawaban Anda sebagai benar.
Justin Dearing
3
+1 Setuju dengan Mark. Khawatir tentang fragmentasi ketika Anda benar-benar memiliki beberapa data. :-)
Aaron Bertrand
Saya benar-benar memahami apa yang Anda katakan. Tapi karena penasaran, apakah ini karena mesin db tidak dapat mendefrag beberapa halaman? Maksudku, pasti ada alasan untuk ini.
Thomas Stringer
3
Bukannya tidak bisa, tetapi mengapa itu mengganggu? Melakukan hal itu akan membuat sedikit atau tidak berdampak pada I / O - terutama karena tabel ini kecil hampir dijamin dalam memori.
Aaron Bertrand
1
Hanya. Sepertinya aneh, itu saja. Katakanlah saya sedang menulis aplikasi untuk memeriksa dan melaporkan fragmentasi indeks, saya harus menambahkan logika tambahan untuk tidak hanya menguji persentase frag, tetapi juga jumlah halaman sehingga tidak ada alarm palsu.
Thomas Stringer
19

Kutipan dari " Praktik Terbaik Defragmentasi Indeks Microsoft SQL Server 2000 ":

"Fragmentasi mempengaruhi disk I / O. Oleh karena itu, fokuslah pada indeks yang lebih besar karena halaman mereka cenderung tidak di-cache oleh SQL Server. Gunakan jumlah halaman yang dilaporkan oleh DBCC SHOWCONTIG untuk mendapatkan gambaran tentang ukuran indeks (setiap halaman adalah 8 KB) Biasanya, Anda tidak perlu khawatir dengan tingkat indeks fragmentasi dengan kurang dari 1.000 halaman. Dalam tes, indeks yang berisi lebih dari 10.000 halaman menyadari kenaikan kinerja, dengan kenaikan terbesar pada indeks dengan halaman yang jauh lebih banyak secara signifikan (lebih besar lebih dari 50.000 halaman) . "

Jadi, jawaban semacam ini adalah pertanyaan Anda dan mendukung jawaban Markus dan Harun.

Anda dapat menemukan informasi yang baik tentang fragmentasi indeks dalam artikel berikut dari Brent Ozar:

Juga samudera info hebat tentang indeks secara umum (juga tentang masalah fragmentasi) dapat ditemukan di blog Kimberly Tripp .

Marian
sumber
12

Ini tidak dimaksudkan untuk menjawab pertanyaan Anda, tetapi tidak akan pernah cocok dalam komentar. Anda dapat membuat skrip ini secara dinamis tanpa harus menyalin & menempelkan output ke jendela lain. Mempertimbangkan bahwa sama sekali tidak ada alasan untuk REORGANIZEdan kemudian REBUILD:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;
Aaron Bertrand
sumber
Aaron, terima kasih telah menunjukkan sql dinamis, saya sadar sql dinamis, saya tidak akan mengotomatiskan solusi sampai berfungsi. Orang lain yang membaca ini mungkin harus sadar.
Justin Dearing