Saya membuat tabel big_table sesuai dengan skema Anda
create table big_table
(
updatetime datetime not null,
name char(14) not null,
TheData float,
primary key(Name,updatetime)
)
Saya kemudian mengisi tabel dengan 50.000 baris dengan kode ini:
DECLARE @ROWNUM as bigint = 1
WHILE(1=1)
BEGIN
set @rownum = @ROWNUM + 1
insert into big_table values(getdate(),'name' + cast(@rownum as CHAR), cast(@rownum as float))
if @ROWNUM > 50000
BREAK;
END
Menggunakan SSMS, saya kemudian menguji kedua kueri dan menyadari bahwa dalam kueri pertama Anda mencari MAX TheData dan di kedua, MAX dari updatetime
Saya memodifikasi permintaan pertama untuk mendapatkan MAX dari updatetime
set statistics time on -- execution time
set statistics io on -- io stats (how many pages read, temp tables)
-- query 1
SELECT MAX([UpdateTime])
FROM big_table
-- query 2
SELECT MAX([UpdateTime]) AS value
from
(
SELECT [UpdateTime]
FROM big_table
group by [UpdateTime]
) as t
set statistics time off
set statistics io off
Menggunakan Waktu Statistik, saya mendapatkan kembali jumlah milidetik yang diperlukan untuk mem-parsing, mengkompilasi, dan mengeksekusi setiap pernyataan
Menggunakan Statistik IO saya mendapatkan kembali informasi tentang aktivitas disk
WAKTU STATISTIK dan STATISTIK IO memberikan informasi yang berguna. Seperti tabel sementara yang digunakan (ditunjukkan oleh meja kerja). Juga berapa banyak halaman logis yang dibaca dibaca yang menunjukkan jumlah halaman database yang dibaca dari cache.
Saya kemudian mengaktifkan paket Eksekusi dengan CTRL + M (aktif menunjukkan rencana eksekusi aktual) dan kemudian mengeksekusi dengan F5.
Ini akan memberikan perbandingan kedua pertanyaan.
Ini adalah output dari Tab Pesan
- Pertanyaan 1
Tabel 'big_table'. Pindai hitungan 1, bacaan logis 543 , bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Waktu Eksekusi SQL Server:
Waktu CPU = 16 ms, waktu yang berlalu = 6 ms .
- Pertanyaan 2
Tabel 'Meja Kerja '. Pindai jumlah 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca-depan 0.
Tabel 'big_table'. Pindai hitungan 1, bacaan logis 543 , bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Waktu Eksekusi SQL Server:
Waktu CPU = 0 ms, waktu yang berlalu = 35 ms .
Kedua kueri menghasilkan 543 bacaan logis, tetapi kueri kedua memiliki waktu yang telah berlalu 35ms sedangkan yang pertama hanya memiliki 6ms. Anda juga akan melihat bahwa hasil kueri kedua dalam penggunaan tabel sementara di tempdb, ditunjukkan oleh kata meja kerja . Meskipun semua nilai untuk tabel kerja adalah 0, pekerjaan masih dilakukan di tempdb.
Lalu ada output dari tab rencana Eksekusi yang sebenarnya di sebelah tab Pesan
Menurut rencana eksekusi yang disediakan oleh MSSQL, permintaan kedua yang Anda berikan memiliki total biaya batch 64% sedangkan yang pertama hanya biaya 36% dari total batch, sehingga permintaan pertama membutuhkan lebih sedikit pekerjaan.
Menggunakan SSMS, Anda dapat menguji dan membandingkan kueri Anda dan mencari tahu bagaimana MSSQL mem-parsing kueri Anda dan objek apa: tabel, indeks, dan / atau statistik jika ada yang digunakan untuk memenuhi kueri tersebut.
Satu catatan tambahan yang perlu diingat ketika pengujian adalah membersihkan cache sebelum pengujian, jika memungkinkan. Ini membantu untuk memastikan bahwa perbandingan akurat dan ini penting ketika memikirkan aktivitas disk. Saya mulai dengan DBCC DROPCLEANBUFFERS dan DBCC FREEPROCCACHE untuk menghapus semua cache. Berhati-hatilah meskipun tidak menggunakan perintah ini pada server produksi yang benar-benar digunakan karena Anda akan secara efektif memaksa server untuk membaca semuanya dari disk ke dalam memori.
Ini dokumentasi yang relevan.
- Bersihkan cache rencana dengan DBCC FREEPROCCACHE
- Hapus semuanya dari kumpulan buffer dengan DBCC DROPCLEANBUFFERS
Menggunakan perintah ini mungkin tidak dimungkinkan tergantung pada bagaimana lingkungan Anda digunakan.
Diperbarui 10/28 12:46
Membuat koreksi pada gambar rencana eksekusi dan output statistik.
getdate()
keluar dari loopPenulisan ulang mungkin membantu jika SQL Server menerapkan indeks skip-scan, tetapi tidak.
Index skip-scan memungkinkan mesin basis data untuk mencari nilai indeks yang berbeda berikutnya daripada memindai semua duplikat (atau sub-kunci yang tidak relevan) di antaranya. Dalam kasus Anda, lewati-pindai akan memungkinkan mesin menemukan
MAX(UpdateTime)
yang pertamaName
, melompat keMAX(UpdateTime)
yang keduaName
... dan seterusnya. Langkah terakhir adalah menemukanMAX(UpdateTime)
kandidat dari satu nama.Anda dapat mensimulasikan ini sampai batas tertentu menggunakan CTE rekursif, tetapi ini agak berantakan, dan tidak seefisien skip-scan bawaan:
Rencana itu melakukan pencarian tunggal untuk masing-masing yang berbeda
Name
, kemudian menemukan yang tertinggiUpdateTime
dari kandidat. Performanya relatif terhadap pemindaian penuh sederhana dari tabel tergantung pada berapa banyak duplikat yang ada perName
, dan apakah halaman yang disentuh oleh singleton berusaha dalam memori atau tidak.Solusi alternatif
Jika Anda dapat membuat indeks baru di tabel ini, pilihan yang baik untuk kueri ini adalah indeks
UpdateTime
sendiri:Indeks ini akan memungkinkan mesin eksekusi menemukan yang tertinggi
UpdateTime
dengan pencarian tunggal ke akhir indeks b-tree:Paket ini hanya menggunakan beberapa IO logis (untuk menavigasi level b-tree) dan segera menyelesaikannya. Perhatikan bahwa Pemindaian Indeks dalam paket tersebut bukan pemindaian penuh indeks baru - hanya mengembalikan satu baris dari 'ujung' indeks.
Jika Anda tidak ingin membuat indeks baru yang lengkap di atas meja, Anda dapat mempertimbangkan tampilan yang diindeks berisi hanya nilai-
UpdateTime
nilai unik :Ini memiliki keuntungan hanya dengan membuat struktur dengan baris sebanyak-banyaknya karena ada
UpdateTime
nilai unik , meskipun setiap kueri yang mengubah data dalam tabel dasar akan memiliki operator tambahan yang ditambahkan ke rencana pelaksanaannya untuk mempertahankan tampilan yang diindeks. Kueri untuk menemukan nilai maksimumUpdateTime
adalah:sumber