Saya memiliki laporan yang menunjukkan jumlah acara selama 12 jam terakhir, dikelompokkan berdasarkan jam. Kedengarannya cukup mudah, tetapi yang saya perjuangkan adalah bagaimana memasukkan catatan yang menutupi kesenjangan.
Ini adalah contoh tabel:
Event
(
EventTime datetime,
EventType int
)
Data terlihat seperti ini:
'2012-03-08 08:00:04', 1
'2012-03-08 09:10:00', 2
'2012-03-08 09:11:04', 2
'2012-03-08 09:10:09', 1
'2012-03-08 10:00:17', 4
'2012-03-08 11:00:04', 1
Saya perlu membuat set hasil yang memiliki satu catatan untuk setiap jam selama 12 jam terakhir, terlepas dari ada peristiwa selama jam itu atau tidak.
Dengan asumsi waktu saat ini adalah '2012-03-08 11:00:00', laporan akan menunjukkan (kurang-lebih):
Hour EventCount
---- ----------
23 0
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 1
9 3
10 1
Saya datang dengan solusi yang menggunakan tabel yang memiliki satu catatan untuk setiap jam dalam sehari. Saya berhasil mendapatkan hasil yang saya cari menggunakan UNION dan beberapa logika kasus yang berbelit-belit di klausa mana, tetapi saya berharap seseorang memiliki solusi yang lebih elegan.
sumber
Tabel penghitungan dapat digunakan untuk hal-hal seperti ini. Mereka bisa sangat efisien. Buat tabel penghitungan di bawah ini. Saya membuat tabel penghitungan dengan hanya 24 baris untuk contoh Anda, tetapi Anda dapat membuatnya dengan berapa pun Anda ingin sesuai dengan tujuan lain.
Saya berasumsi meja Anda disebut dbo.tblEvents, jalankan kueri di bawah ini. Saya percaya ini yang Anda cari:
Saya percaya kredit diberikan ke tautan berikut, saya percaya ini adalah tempat saya pertama kali menemukan ini:
http://www.sqlservercentral.com/articles/T-SQL/62867/
http://www.sqlservercentral.com/articles/T-SQL/74118/
sumber
Pertama, permintaan maaf saya atas keterlambatan respons saya sejak komentar terakhir saya.
Subjek muncul dalam komentar yang menggunakan CTE Rekursif (rCTE dari sini) berjalan cukup cepat karena rendahnya jumlah baris. Meskipun mungkin terlihat seperti itu, tidak ada yang lebih jauh dari kebenaran.
BANGUN TALLY TABLE DAN FUNGSI TALLY
Sebelum kita memulai pengujian, kita perlu membuat Tabel Tally fisik dengan Indeks Clustered yang sesuai dan Fungsi Tally gaya Itzik Ben-Gan. Kami juga akan melakukan semua ini di TempDB sehingga kami tidak sengaja menjatuhkan barang siapa pun.
Berikut kode untuk membuat Tally Table dan versi produksi saya saat ini dari kode hebat Itzik.
Ngomong-ngomong ... perhatikan bahwa membangun jutaan dan satu baris Tabel Tally dan menambahkan Indeks Clustered ke dalam sekitar satu detik atau lebih. Coba ITU dengan rCTE dan lihat berapa lama! ;-)
BANGUN BEBERAPA DATA UJI
Kami juga membutuhkan beberapa data uji. Ya, saya setuju bahwa semua fungsi yang akan kami uji, termasuk rCTE, berjalan dalam milidetik atau kurang untuk hanya 12 baris tetapi itulah jebakan yang banyak orang jatuh ke dalamnya. Kita akan berbicara lebih banyak tentang jebakan itu nanti, tetapi, untuk saat ini, mari kita simulasikan memanggil setiap fungsi 40.000 kali, yaitu berapa kali fungsi-fungsi tertentu di toko saya dipanggil dalam 8 jam sehari. Bayangkan saja berapa kali fungsi seperti itu dapat disebut dalam bisnis ritel online besar.
Jadi, inilah kode untuk membangun 40.000 baris dengan tanggal acak, masing-masing memiliki Nomor Baris hanya untuk tujuan pelacakan. Saya tidak meluangkan waktu untuk membuat waktu penuh karena itu tidak masalah di sini.
MEMBANGUN BEBERAPA FUNGSI UNTUK MELAKUKAN HAL 12 JAM
Selanjutnya, saya mengonversi kode rCTE ke fungsi dan membuat 3 fungsi lainnya. Semuanya telah dibuat sebagai iTVF kinerja tinggi (Inline Table Valued Functions). Anda selalu bisa tahu karena iTVF tidak pernah memiliki BEGIN di dalamnya seperti Scalar atau mTVF (Multi-statement Table Valued Functions).
Inilah kode untuk membangun 4 fungsi itu ... Saya menamainya setelah metode yang mereka gunakan dan bukan apa yang mereka lakukan hanya untuk membuatnya lebih mudah untuk mengidentifikasi mereka.
MEMBANGUN UJI HARNESS UNTUK MENGUJI FUNGSI
Terakhir namun tidak kalah pentingnya, kami membutuhkan test harness. Saya melakukan pemeriksaan awal dan kemudian menguji setiap fungsi dengan cara yang identik.
Berikut kode untuk alat uji ...
Satu hal yang perlu diperhatikan dalam test harness di atas adalah bahwa saya shunt semua output menjadi variabel "throwaway". Itu untuk mencoba menjaga pengukuran kinerja semurni mungkin tanpa output ke disk atau hasil skewing layar.
KATA PERHATIAN PADA SET STATISTIK
Juga, kata hati-hati untuk calon penguji ... Anda TIDAK HARUS menggunakan STATISTIK SET ketika menguji fungsi Scalar atau mTVF. Itu hanya dapat digunakan dengan aman pada fungsi iTVF seperti yang ada dalam tes ini. SET STATISTIK telah terbukti membuat fungsi SCALAR berjalan ratusan kali lebih lambat dari yang sebenarnya mereka lakukan tanpanya. Ya, saya mencoba memiringkan kincir angin lain, tetapi itu akan menjadi posting panjang artikel yang lebih gila dan saya tidak punya waktu untuk itu. Saya memiliki artikel tentang SQLServerCentral.com yang membicarakan semua itu tetapi tidak ada gunanya memposting tautan di sini karena seseorang akan merasa tidak nyaman dengan hal itu.
HASIL UJI
Jadi, inilah hasil tes ketika saya menjalankan test harness pada laptop i5 kecil saya dengan RAM 6GB.
"BASELINE SELECT", yang hanya memilih data (setiap baris dibuat 12 kali untuk mensimulasikan volume pengembalian yang sama), muncul tepat sekitar 1/5 detik. Yang lainnya masuk sekitar seperempat detik. Ya, semuanya kecuali fungsi RCTE yang berdarah. Butuh 4 dan 1/4 detik atau 16 kali lebih lama (1.600% lebih lambat).
Dan lihat bacaan logis (memori IO) ... RCTE menghabiskan 2.960.000 (hampir 3 JUTI berbunyi) sedangkan fungsi lainnya hanya mengkonsumsi sekitar 82.100. Itu berarti rCTE mengkonsumsi IO memori lebih dari 34,3 kali lebih banyak daripada fungsi lainnya.
PIKIRAN PENUTUP
Mari kita simpulkan. Metode rCTE untuk melakukan hal "kecil" 12 baris ini menggunakan 16 KALI (1.600%) lebih banyak CPU (dan durasi) dan 34.3 KALI (3.430%) lebih banyak memori IO daripada fungsi lainnya.
Heh ... Saya tahu apa yang Anda pikirkan. "Kesepakatan Besar! Hanya satu fungsi."
Ya, setuju, tetapi berapa banyak fungsi lain yang Anda miliki? Berapa banyak tempat lain di luar fungsi yang Anda miliki? Dan apakah Anda memiliki salah satu dari mereka yang bekerja dengan lebih dari 12 baris setiap kali dijalankan? Dan, apakah ada kemungkinan bahwa seseorang yang sedang dalam kesulitan untuk metode dapat menyalin kode rCTE untuk sesuatu yang jauh lebih besar?
Ok, waktunya untuk berterus terang. Sangat tidak masuk akal bagi orang untuk membenarkan kode yang ditantang kinerja hanya karena dugaan jumlah baris atau penggunaan yang terbatas. Kecuali ketika Anda membeli kotak MPP dengan harga jutaan dolar (belum lagi biaya penulisan ulang kode untuk membuatnya bekerja pada mesin seperti itu), Anda tidak dapat membeli mesin yang menjalankan kode Anda 16 kali lebih cepat (SSD menang lakukan juga ... semua ini ada dalam memori berkecepatan tinggi ketika kami mengujinya). Kinerja ada dalam kode. Performa bagus dalam kode yang baik.
Bisakah Anda bayangkan jika semua kode Anda berjalan "hanya" 16 kali lebih cepat?
Jangan sekali-kali menjustifikasi kode yang bermasalah atau kinerja bermasalah pada jumlah baris rendah atau bahkan penggunaan rendah. Jika Anda melakukannya, Anda mungkin harus meminjam salah satu kincir angin yang saya tuduh miringkan agar CPU dan disk Anda cukup dingin. ;-)
KATA TENTANG KATA "BENAR-BENAR"
Ya saya setuju. Berbicara secara semantik, Tally Table berisi angka, bukan "penghitungan". Dalam artikel asli saya pada subjek (itu bukan artikel asli tentang teknik tetapi itu adalah pertama saya di atasnya), saya menyebutnya "Tally" bukan karena apa yang dikandungnya, tetapi karena apa yang dilakukannya ... itu digunakan untuk "menghitung" alih-alih perulangan dan "Tally" sesuatu berarti "Menghitung" sesuatu. ;-) Sebut saja apa yang Anda akan ... Tabel Angka, Tabel Penghitungan, Tabel Urutan, apa pun. Saya tidak peduli. Bagi saya, "Tally" lebih berarti penuh dan, karena menjadi DBA malas yang baik, hanya berisi 5 huruf (2 identik) daripada 7 dan lebih mudah untuk mengatakan bagi kebanyakan orang. Ini juga "tunggal", yang mengikuti konvensi penamaan saya untuk tabel. ;-) Itu' S juga apa artikel yang berisi halaman dari buku dari 60-an menyebutnya. Saya akan selalu menyebutnya sebagai "Tally Table" dan Anda akan tetap tahu apa yang saya atau orang lain maksudkan. Saya juga menghindari Notasi Hongaria seperti wabah tetapi menyebut fungsi "fnTally" sehingga saya bisa mengatakan "Yah, jika Anda menggunakan fungsi Tally ef-en yang saya tunjukkan, Anda tidak akan memiliki masalah kinerja" tanpa benar-benar menjadi Pelanggaran SDM. ;-) tanpa itu sebenarnya menjadi pelanggaran SDM. ;-) tanpa itu sebenarnya menjadi pelanggaran SDM. ;-)
Yang lebih saya pedulikan adalah orang-orang yang belajar menggunakannya dengan benar alih-alih menggunakan hal-hal seperti rCTE yang menantang kinerja dan bentuk-bentuk lain dari RBAR Tersembunyi.
sumber
Anda perlu
RIGHT JOIN
data Anda dengan kueri yang mengembalikan satu catatan untuk setiap jam yang Anda butuhkan.Lihat ini untuk beberapa cara untuk mendapatkan nomor baris yang kemudian dapat Anda kurangi sebagai jam dari waktu saat ini.
Di Oracle, kueri hierarki pada dual akan menghasilkan baris:
sumber