Saya membandingkan dua kueri di SQL Server 2012. Tujuannya adalah untuk menggunakan semua informasi terkait yang tersedia dari pengoptimal kueri saat memilih kueri terbaik. Kedua pertanyaan menghasilkan hasil yang sama; pesanan maksimum untuk semua pelanggan.
Membersihkan kumpulan buffer dilakukan sebelum menjalankan setiap permintaan dengan FREEPROCCACHE dan DROPCLEANBUFFERS
Menggunakan informasi yang disediakan di bawah ini, pertanyaan apa yang merupakan pilihan yang lebih baik?
-- Query 1 - return the maximum order id for a customer
SELECT orderid, custid
FROM Sales.Orders AS O1
WHERE orderid = (SELECT MAX(O2.orderid)
FROM Sales.Orders AS O2
WHERE O2.custid = O1.custid);
-- Query 2 - return the maximum order id for a customer
SELECT MAX(orderid), custid
FROM Sales.Orders AS O1
group by custid
order by custid
WAKTU STATISTIK
Kueri 1 WAKTU STATISTIK: Waktu CPU = 0ms, waktu yang berlalu = 24 ms
Kueri 2 WAKTU STATISTIK: Waktu CPU = 0 ms, waktu yang berlalu = 23 ms
STATISTIK IO
Kueri 1 STATISTIK IO: Tabel 'Pesanan'. Pindai hitungan 1, bacaan logis 5, bacaan fisik 2, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Kueri 2 STATISTIK IO: Tabel 'Pesanan'. Pindai hitungan 1, bacaan logis 4, bacaan fisik 1, bacaan baca-depan 8, bacaan logis lob 0, bacaan fisik lob 0, bacaan lob baca-depan 0.
Rencana Eksekusi
SELECT properties Permintaan 1
SELECT properties Query 2
Kesimpulan:
Pertanyaan 1
- Biaya batch 48%
- Bacaan Logis 5
- Bacaan Fisik 2
- Baca-depan Dibaca: 0
- Waktu CPU: 0ms
- Waktu Berlalu 24ms
- Perkiraan biaya subtree: 0,0050276
- CompileCPU: 2
- CompileMemory: 384
- CompileTime: 2
Pertanyaan 2
- Biaya batch 52%
- Bacaan Logis 4
- Bacaan Fisik 1
- Baca-depan Dibaca: 8
- Waktu CPU 0
- Waktu Berlalu 23ms
- Perkiraan biaya subtree: 0,0054782
- CompileCPU: 0
- CompileMemory: 192
- CompileTime: 0
Secara pribadi, meskipun Permintaan 2 memiliki biaya batch yang lebih tinggi sesuai dengan rencana grafis, saya pikir ini lebih efisien daripada Permintaan 1. Ini karena permintaan 2 membutuhkan pembacaan yang kurang logis, memiliki waktu berlalu yang sedikit lebih rendah, nilai compilecpu, compilememory dan compiletime adalah menurunkan. baca baca depan adalah 8 untuk kueri 2 dan 0 untuk kueri 1.
Perbarui 12:03
Definisi Indeks Berkerumun
ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
[orderid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Indeks Non-Clustered idx_nc_custid
CREATE NONCLUSTERED INDEX [idx_nc_custid] ON [Sales].[Orders]
(
[custid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
sumber
Jawaban:
Saya suka pendekatan Anda dengan pertimbangan yang cermat untuk mencari opsi dan paket yang dicari. Saya berharap lebih banyak pengembang melakukan ini. Satu peringatan akan - selalu menguji dengan banyak baris, melihat bacaan logis, ini adalah tabel bertubuh kecil. Coba dan hasilkan sampel load dan jalankan kueri lagi. Satu masalah kecil - di kueri teratas Anda, Anda tidak meminta pesanan oleh, di kueri bawah Anda. Anda harus membandingkan dan membedakan mereka masing-masing dengan pemesanan.
Saya baru saja dengan cepat membuat tabel SalesOrders dengan 200.000 pesanan penjualan di dalamnya - masih tidak besar dengan imajinasi. Dan menjalankan kueri dengan ORDER OLEH di masing-masing. Saya juga bermain dengan indeks sedikit.
Tanpa indeks berkerumun di OrderID, hanya indeks non-berkerumun di CustID Kueri kedua mengungguli. Apalagi dengan urutan yang termasuk dalam masing-masing. Ada dua kali lebih banyak bacaan pada kueri pertama dari kueri kedua, dan persentase biaya adalah 67% / 33% antara kueri.
Dengan indeks berkerumun di OrderID dan indeks non-berkerumun di CustID, mereka melakukan dalam kecepatan yang sama dan jumlah pembacaan yang sama persis.
Jadi saya sarankan Anda meningkatkan jumlah baris dan melakukan beberapa pengujian lagi. Tapi analisis terakhir saya pada pertanyaan Anda -
Anda mungkin menemukan mereka berperilaku lebih mirip daripada yang Anda sadari ketika Anda meningkatkan baris, jadi ingatlah peringatan itu dan uji seperti itu.
Jika semua yang Anda ingin kembalikan adalah OrderID maksimum untuk setiap Pelanggan, dan Anda ingin menentukan bahwa dengan OrderID menjadi OrderID terbesar maka permintaan kedua dari keduanya adalah cara terbaik untuk keluar dari pola pikir saya - ini sedikit lebih sederhana dan walaupun sedikit lebih mahal berdasarkan biaya subtree itu adalah pernyataan yang lebih cepat dan lebih mudah untuk menguraikan. Jika Anda berniat menambahkan kolom lain ke dalam set hasil Anda suatu hari nanti? Maka permintaan pertama memungkinkan Anda melakukan itu.
Diperbarui: Salah satu komentar Anda di bawah pertanyaan Anda adalah:
Tapi takeaway terbaik untuk melakukan itu- uji dengan lebih banyak data - selalu memastikan Anda memiliki data yang konsisten dengan produksi dan produksi yang diharapkan di masa depan. Paket kueri mulai mencari data saat Anda memberikan lebih banyak baris ke tabel, dan mencoba dan menjaga distribusi apa yang Anda harapkan dalam produksi. Dan perhatikan hal-hal seperti termasuk Order By atau tidak, di sini saya tidak berpikir itu membuat sedikit perbedaan pada akhirnya, tetapi masih layak untuk digali.
Pendekatan Anda membandingkan tingkat detail dan data ini bagus. Sebagian besar biaya subtree sewenang-wenang dan tidak berarti, tetapi masih layak setidaknya mencari perbandingan antara pengeditan / perubahan atau bahkan antara permintaan. Melihat statistik waktu dan IO cukup penting, seperti juga melihat rencana untuk apa pun yang terasa tidak pada tempatnya untuk ukuran data yang Anda kerjakan dan apa yang Anda coba lakukan.
sumber