Sebagai jawaban lain sudah menunjukkan SQL Server mungkin atau mungkin tidak secara eksplisit memastikan bahwa baris diurutkan dalam urutan indeks berkerumun sebelum insert
.
Ini tergantung pada apakah operator indeks berkerumun dalam rencana memiliki DMLRequestSort
set properti (yang pada gilirannya tergantung pada perkiraan jumlah baris yang dimasukkan).
Jika Anda menemukan bahwa SQL Server meremehkan ini untuk alasan apa pun Anda mungkin mendapat manfaat dari menambahkan secara eksplisit ORDER BY
ke SELECT
kueri untuk meminimalkan pemisahan halaman dan selanjutnya fragmentasi dari INSERT
operasi
Contoh:
use tempdb;
GO
CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))
CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))
GO
DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)
INSERT INTO @T(N)
SELECT number
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499
/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
/*Same operation using explicit sort*/
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;
SELECT avg_fragmentation_in_percent,
fragment_count,
page_count,
avg_page_space_used_in_percent,
record_count
FROM sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;
Acara yang T
sangat terfragmentasi
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536 92535 92535 67.1668272794663 250000
99.5 200 200 74.2868173956017 92535
0 1 1 32.0978502594514 200
Tetapi untuk T2
fragmentasi minimal
avg_fragmentation_in_percent fragment_count page_count avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376 262 62500 99.456387447492 250000
2.1551724137931 232 232 43.2438349394613 62500
0 1 1 37.2374598468001 232
Sebaliknya kadang-kadang Anda mungkin ingin memaksa SQL Server untuk meremehkan jumlah baris ketika Anda tahu data sudah dipilah sebelumnya dan ingin menghindari jenis yang tidak perlu. Salah satu contoh penting adalah ketika memasukkan sejumlah besar baris ke tabel dengan newsequentialid
kunci indeks berkerumun. Dalam versi SQL Server sebelum Denali SQL Server menambahkan operasi semacam yang tidak perlu dan berpotensi mahal . Ini bisa dihindari dengan
DECLARE @var INT =2147483647
INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar
SQL Server kemudian akan memperkirakan bahwa 100 baris akan dimasukkan terlepas dari ukurannya Bar
yang di bawah ambang batas di mana semacam ditambahkan ke paket. Namun seperti yang ditunjukkan dalam komentar di bawah ini, ini berarti bahwa sisipan sayangnya tidak akan dapat memanfaatkan penebangan minimal.
Jika optimizer memutuskan akan lebih efisien untuk menyortir data sebelum dimasukkan, ia akan melakukannya di suatu tempat di hulu dari operator yang dimasukkan. Jika Anda memperkenalkan pengurutan sebagai bagian dari kueri, pengoptimal harus menyadari bahwa data sudah diurutkan dan dihilangkan melakukannya lagi. Perhatikan bahwa rencana eksekusi yang dipilih dapat bervariasi dari satu menjalankan ke menjalankan tergantung pada jumlah baris yang dimasukkan dari tabel pementasan Anda.
Jika Anda dapat menangkap rencana pelaksanaan proses dengan dan tanpa pengurutan eksplisit, lampirkan di pertanyaan untuk komentar.
Sunting: 2011-10-28 17:00
@Gonsalu menjawab tampaknya menunjukkan bahwa operasi semacam selalu terjadi, ini bukan masalahnya. Diperlukan skrip demo!
Saat skrip semakin besar, saya memindahkannya ke Gist . Untuk memudahkan percobaan, skrip menggunakan mode SQLCMD. Tes dijalankan pada 2K5SP3, dual core, 8GB.
Tes memasukkan mencakup tiga skenario:
Jalankan pertama, memasukkan 25 baris.
Ketiga paket eksekusi adalah sama, tidak ada penguraian yang terjadi di mana pun dalam paket dan pemindaian indeks berkerumun adalah "dipesan = salah".
Jalankan kedua, memasukkan 26 baris.
Kali ini rencananya berbeda.
Jadi, ada titik kritis di mana pengoptimal menganggap semacam itu perlu. Seperti yang ditunjukkan @MartinSmith, ini tampaknya didasarkan pada perkiraan baris yang akan dimasukkan. Pada rig pengujian saya 25 tidak memerlukan pengurutan, 26 tidak (2K5SP3, dual core, 8GB)
Skrip SQLCMD mencakup variabel yang memungkinkan ukuran baris dalam tabel untuk berubah (mengubah kepadatan halaman) dan jumlah baris dalam dbo.MyTable sebelum sisipan tambahan. Dari pengujian saya, tidak ada yang berpengaruh pada titik kritis.
Jika ada pembaca yang cenderung, silakan jalankan skrip dan tambahkan titik kritis Anda sebagai komentar. Tertarik untuk mendengar jika bervariasi di seluruh rig uji dan / atau versi.
Sunting: 2011-10-28 20:15
Tes berulang pada rig yang sama tetapi dengan 2K8R2. Kali ini titik kritis adalah 251 baris. Sekali lagi, memvariasikan kepadatan halaman dan jumlah baris yang ada tidak berpengaruh.
sumber
The
ORDER BY
klausul dalamSELECT
pernyataan berlebihan.Itu berlebihan karena baris yang akan dimasukkan, jika perlu diurutkan , tetap diurutkan.
Mari kita buat test case.
Mari kita aktifkan tampilan teks dari rencana kueri yang sebenarnya, sehingga kita dapat melihat tugas apa yang dilakukan oleh prosesor kueri.
Sekarang, mari kita
INSERT
baris 2K ke tabel tanpaORDER BY
klausa.Paket eksekusi aktual untuk permintaan ini adalah sebagai berikut.
Seperti yang Anda lihat, ada operator Sortir sebelum INSERT yang sebenarnya terjadi.
Sekarang, mari kita hapus tabel, dan
INSERT
baris 2k ke tabel denganORDER BY
klausa.Paket eksekusi aktual untuk permintaan ini adalah sebagai berikut.
Perhatikan bahwa itu adalah rencana eksekusi yang sama yang digunakan untuk
INSERT
pernyataan tanpaORDER BY
klausa.Sekarang,
Sort
operasi tidak selalu diperlukan, seperti yang ditunjukkan Mark Smith dalam jawaban lain (jika jumlah baris yang disisipkan rendah), tetapiORDER BY
klausa masih berlebihan dalam kasus itu, karena bahkan dengan eksplisitORDER BY
, bahkanSort
operasi tidak dihasilkan oleh prosesor kueri.Anda bisa mengoptimalkan
INSERT
pernyataan ke dalam tabel dengan indeks berkerumun, dengan menggunakan log minimalINSERT
, tapi itu di luar cakupan untuk pertanyaan ini.Diperbarui 2011-11-02: Seperti yang ditunjukkan oleh Mark Smith ,
INSERT
masuk ke tabel dengan indeks berkerumun mungkin tidak selalu perlu diurutkan -ORDER BY
klausa juga berlebihan dalam kasus itu, meskipun.sumber