Saya memiliki pertanyaan berikut, dan karena banyak SUM
panggilan fungsi, permintaan saya berjalan terlalu lambat. Saya memiliki banyak catatan di database saya dan saya ingin mendapatkan laporan dari tahun ini dan tahun lalu (30 hari terakhir, 90 hari terakhir dan 365 hari terakhir) untuk masing-masing:
SELECT
b.id as [ID]
,d.[Title] as [Title]
,e.Class as [Class]
,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]
,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]
,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]
,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]
,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]
,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]
FROM
tb1 a
INNER JOIN
tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN
tb3 c on b.fid = c.col5
INNER JOIN
tb4 d on c.id = d.col6
INNER JOIN
tb5 e on c.col7 = e.id
GROUP BY
b.id, d.Title, e.Class
Adakah yang tahu bagaimana cara meningkatkan kueri agar berjalan lebih cepat?
EDIT: Saya didorong untuk memindahkan DATEADD
pemanggilan fungsi ke where
pernyataan dan memuat dua tahun pertama pertama kemudian menyaringnya dalam kolom, tapi saya tidak yakin jawaban yang disarankan dijalankan dan berfungsi, itu bisa ditemukan di sini: https: // stackoverflow. com / a / 59944426/12536284
Jika Anda setuju dengan solusi di atas, tolong tunjukkan kepada saya bagaimana saya bisa menerapkannya dalam permintaan saya saat ini?
Hanya FYI, saya menggunakan SP ini di C #, Entity Framework (DB-First), sesuatu seperti ini:
var result = MyDBEntities.CalculatorSP();
Execution Plan
. Silakan mempostingnyaJawaban:
Seperti yang telah disebutkan, rencana eksekusi akan sangat membantu dalam kasus ini. Berdasarkan apa yang Anda tunjukkan, tampaknya Anda telah mengekstraksi 12 kolom dari 15 kolom total
tb1 (a)
, sehingga Anda dapat mencoba menjalankan kueri Anda tanpa bergabung dan hanya menentangnyatb1
untuk melihat apakah kueri Anda berfungsi seperti yang diharapkan. Karena saya dapat melihat tidak ada yang salah dengan panggilan fungsi SUM Anda, tebakan terbaik saya adalah Anda memiliki masalah dengan gabungan Anda, saya akan menyarankan untuk melakukan hal berikut. Anda dapat mulai dengan mengecualikan bergabung terakhir misalnya,INNER JOIN tb5 e on c.col7 = e.id
dan segala penggunaan terkait sepertie.Class as [Class]
dane.Class
dalam grup Anda dengan pernyataan. Kami tidak akan mengecualikannya sepenuhnya, ini hanya tes untuk memastikan apakah masalahnya ada atau tidak, jika kueri Anda berjalan lebih baik dan seperti yang diharapkan, Anda dapat mencoba menggunakan tabel temp sebagai solusi alih-alih bergabung terakhir , sesuatu seperti ini:Sebenarnya, tabel sementara adalah tabel yang ada sementara di SQL Server. Tabel sementara berguna untuk menyimpan set hasil langsung yang diakses beberapa kali. Anda dapat membaca lebih lanjut tentang ini di sini https://www.sqlservertutorial.net/sql-server-basics/sql-server-turnal-tables/ Dan di sini https://codingsight.com/introduction-to-temporary-tables-in -sql-server /
Saya juga akan sangat menyarankan, jika Anda menggunakan Prosedur Tersimpan, atur
NOCOUNT
keON
, itu juga dapat memberikan peningkatan kinerja yang signifikan, karena lalu lintas jaringan sangat berkurang:Berdasarkan ini :
sumber
tb5
ke#Temp
tabel dan bergabung dengan tabel temp bekerja lebih cepat daripada bergabungtb5
secara langsung? bermuka masam mereka mengandung data yang sama (dan#Temp
mungkin hilang indeks jika itu ada ditb5
). Saya benar-benar tidak mengerti mengapa ini lebih efisien (untuk semua yang saya tahu seharusnya lebih efisien untuk menyalin semua data dan bergabung).tb5
terletak di server lain? Dalam hal ini menggunakan tabel temp jelas lebih cepat daripada langsung bergabung ke server lain. Itu hanya saran untuk menguji dan melihat apakah ada yang berubah. Saya memiliki situasi yang sama di masa lalu, dan tampaknya untungnya tabel temp telah membantu OP juga dalam kasus ini.Pendekatan terbaik adalah memasukkan ke dalam tabel variabel / tabel hash (jika jumlah baris kecil menggunakan variabel tabel atau menggunakan tabel hash jika jumlah baris cukup besar). Kemudian perbarui agregasi dan akhirnya pilih dari tabel variabel atau tabel hash. Diperlukan rencana kueri.
sumber
Saya berasumsi tb1 adalah tabel besar (relatif terhadap tb2, tb3, tb4 dan tb5).
Jika demikian, masuk akal di sini untuk membatasi pemilihan tabel tersebut (dengan klausa WHERE).
Jika hanya sebagian kecil dari tb1 digunakan, misalnya karena bergabung dengan tb2, tb3, tb4 dan tb5 mengurangi baris yang dibutuhkan hanya beberapa persen, maka Anda harus memeriksa apakah tabel diindeks pada kolom yang Anda gunakan dalam gabungan. .
Jika sebagian besar tb1 digunakan, maka masuk akal untuk mengelompokkan hasilnya sebelum bergabung ke tb2, tb3, tb4 dan tb5. Di bawah ini adalah contohnya.
sumber
Cukup gunakan kolum terkomputasi
Contoh
Tentukan Kolom yang Dihitung dalam Tabel
sumber
Untuk mengoptimalkan perhitungan seperti itu, Anda dapat mempertimbangkan untuk terlebih dahulu menghitung beberapa nilai. Gagasan pra-perhitungan adalah untuk mengurangi jumlah baris yang perlu dibaca atau diproses.
Salah satu cara untuk mencapai ini adalah menggunakan tampilan yang diindeks dan meninggalkan mesin untuk melakukan perhitungan dengan sendirinya. Karena jenis tampilan ini memiliki beberapa keterbatasan, Anda akhirnya membuat tabel sederhana dan melakukan perhitungan sebagai gantinya. Pada dasarnya, itu tergantung pada kebutuhan bisnis.
Jadi, dalam contoh di bawah ini saya membuat tabel dengan
RowID
danRowDatetime
kolom dan memasukkan 1 juta baris. Saya menggunakan tampilan yang diindeks untuk menghitung entitas per hari, jadi alih-alih meminta 1 juta baris per tahun, saya akan meminta 365 baris per tahun untuk menghitung metrik ini.Keberhasilan solusi semacam itu sangat tergantung pada bagaimana data didistribusikan dan berapa banyak baris yang Anda miliki. Misalnya, jika Anda memiliki satu entri per hari untuk setiap hari dalam setahun, tampilan dan tabel akan memiliki kecocokan baris yang sama, sehingga operasi I / O tidak akan berkurang.
Selain itu, di atas hanyalah contoh mematerialisasi data dan membacanya. Dalam kasus Anda, Anda mungkin perlu menambahkan lebih banyak kolom definisi tampilan.
sumber
Saya akan menggunakan tabel pencarian "Tanggal" untuk bergabung dengan data saya dengan indeks pada DatesId. Saya menggunakan tanggal sebagai filter ketika saya ingin menelusuri data historis. Gabung cepat dan penyaringan sebagai DatesId dikelompokkan indeks utama (primary key). Tambahkan kolom tanggal (termasuk kolom) untuk tabel data Anda juga.
Tabel tanggal memiliki kolom-kolom berikut:
Tanggal, Tanggal, Tahun, Kuartal, Tahun Kuarter, MonthNum, MonthName Short, YearWeek, WeekNum, DayOfYear, DayOfMonth, DayNumOfWeek, DayName
Contoh data: 20310409 2031-04-09 2031 2 2031-Q2 4 April 2031_15 15 99 9 3 Rabu
Anda dapat PM saya jika Anda ingin csv ini sehingga Anda dapat mengimpornya ke database, tapi saya yakin Anda dapat dengan mudah menemukan sesuatu seperti ini secara online dan membuat sendiri.
Saya menambahkan kolom identitas juga sehingga Anda bisa mendapatkan bilangan bulat untuk setiap tanggal. Ini membuatnya sedikit lebih mudah untuk dikerjakan, tetapi bukan keharusan.
Ini memungkinkan saya untuk dengan mudah melompat kembali ke periode tertentu. Sangat mudah untuk membuat pandangan Anda sendiri tentang ini. Tentu saja Anda dapat menggunakan fungsi ROW_NUMBER () untuk melakukan ini selama bertahun-tahun, minggu, dll.
Setelah saya memiliki daterange yang saya inginkan, saya bergabung ke data. Bekerja sangat cepat!
sumber
Karena Anda selalu mengelompokkan nilai berdasarkan seluruh jumlah bulan, saya pertama kali akan mengelompokkan berdasarkan bulan dalam subquery di dalam dari klausa. Ini mirip dengan menggunakan tabel sementara. Tidak yakin apakah ini akan mempercepat permintaan Anda.
sumber
Untuk meningkatkan kecepatan permintaan SQL, Anda harus menambahkan indeks. Untuk setiap tabel yang digabung, Anda harus menambahkan satu indeks.
Seperti contoh kode ini untuk oracle:
sumber