Jelek. Seperti itulah tampilan data yang tidak disortir. Kami membuat data mudah dilihat dengan menyortirnya. Dan untuk itulah SQL ORDER BY. Gunakan satu atau beberapa kolom atau ekspresi sebagai dasar untuk mengurutkan data. Kemudian, tambahkan ASC atau DESC untuk mengurutkan naik atau turun.
Sintaks SQL ORDER BY:
ORDER BY <order_by_expression> [ASC | DESC]
Ekspresi ORDER BY bisa sesederhana daftar kolom atau ekspresi. Itu juga bisa bersyarat menggunakan blok CASE WHEN.
Ini sangat fleksibel.
Anda juga dapat menggunakan paging melalui OFFSET dan FETCH. Tentukan jumlah baris yang akan dilewati dan baris yang akan ditampilkan.
Tapi ini kabar buruknya.
Menambahkan ORDER BY ke kueri Anda dapat memperlambatnya. Dan beberapa peringatan lain dapat membuat ORDER BY “tidak berfungsi.” Anda tidak bisa hanya menggunakannya kapan saja Anda mau, karena mungkin ada hukumannya. Jadi, apa yang harus kita lakukan?
Pada artikel ini, kita akan membahas apa yang harus dan tidak boleh dilakukan dalam menggunakan ORDER BY. Setiap item akan menangani masalah, dan solusi akan mengikuti.
Siap?
Lakukan di SQL ORDER BY
1. Indeks SQL ORDER BY Column
Indeks adalah semua tentang pencarian cepat. Dan memiliki satu di kolom yang Anda gunakan dalam klausa ORDER BY dapat mempercepat kueri Anda.
Mari kita mulai menggunakan ORDER BY dalam kolom tanpa indeks. Kami akan menggunakan AdventureWorks sampel basis data. Sebelum menjalankan kueri di bawah, nonaktifkan IX_SalesOrderDetail_ProductID indeks di SalesOrderDetail meja. Kemudian, tekan Ctrl-M dan jalankan.
-- Get order details by product and sort them by ProductID
USE AdventureWorks
GO
SET STATISTICS IO ON
GO
SELECT
ProductID
,OrderQty
,UnitPrice
,LineTotal
FROM Sales.SalesOrderDetail
ORDER BY ProductID
SET STATISTICS IO OFF
GO
ANALISIS
Kode di atas akan menampilkan statistik I/O di tab Pesan di SQL Server Management Studio. Anda akan melihat rencana eksekusi di tab lain.
TANPA INDEKS
Pertama, mari dapatkan pembacaan logis dari STATISTICS IO. Lihat Gambar 1.
Gambar 1 . Pembacaan logis menggunakan ORDER BY dari kolom yang tidak diindeks. (Diformat menggunakan statisticsparser.com )
Tanpa indeks, kueri menggunakan 1.313 pembacaan logis. Dan Meja Kerja . itu ? Artinya SQL Server menggunakan TempDB untuk memproses penyortiran.
Tapi apa yang terjadi di balik layar? Mari kita periksa rencana eksekusi pada Gambar 2.
Gambar 2 . Rencana eksekusi kueri menggunakan ORDER BY dari kolom yang tidak diindeks.
Apakah Anda melihat operator Paralelisme (Gather Streams) itu? Itu berarti SQL Server menggunakan lebih dari 1 prosesor untuk memproses kueri ini. Kuerinya cukup berat sehingga membutuhkan lebih banyak CPU.
Jadi, bagaimana jika SQL Server menggunakan TempDB dan lebih banyak prosesor? Ini buruk untuk kueri sederhana.
DENGAN INDEKS
Bagaimana tarifnya jika indeks diaktifkan kembali? Mari kita cari tahu. Bangun kembali indeks IX_SalesOrderDetail_ProductID . Kemudian, jalankan kembali kueri di atas.
Periksa pembacaan logis baru pada Gambar 3.
Gambar 3 . Pembacaan logis baru setelah membangun kembali indeks.
Ini jauh lebih baik. Kami memotong jumlah pembacaan logis hampir setengahnya. Itu berarti indeks membuatnya mengkonsumsi lebih sedikit sumber daya. Dan Meja Kerja ? Itu hilang! Tidak perlu menggunakan TempDB .
Dan rencana eksekusi? Lihat Gambar 4.
Gambar 4 . Rencana eksekusi baru lebih sederhana ketika indeks dibangun kembali.
Lihat? Rencananya lebih sederhana. Tidak perlu CPU tambahan untuk mengurutkan 121.317 baris yang sama.
Jadi, intinya adalah:Pastikan kolom yang Anda gunakan untuk ORDER BY diindeks .
TAPI BAGAIMANA JIKA MENAMBAHKAN INDEKS MEMPENGARUHI KINERJA TULIS?
Pertanyaan bagus.
Jika itu masalahnya, Anda dapat membuang sebagian tabel sumber ke tabel sementara atau tabel dengan memori yang dioptimalkan . Kemudian, indeks tabel itu. Gunakan yang sama jika lebih banyak tabel yang terlibat. Kemudian, nilai kinerja kueri dari opsi yang Anda pilih. Opsi yang lebih cepat akan menjadi pemenangnya.
2. Batasi Hasil dengan WHERE dan OFFSET/FETCH
Mari kita gunakan kueri yang berbeda. Katakanlah Anda perlu menampilkan informasi produk dengan gambar di aplikasi. Gambar dapat membuat kueri menjadi lebih berat. Jadi, kami tidak hanya akan memeriksa pembacaan logis tetapi juga pembacaan logis lob.
Ini kodenya.
SET STATISTICS IO ON
GO
SELECT
a.ProductID
,a.Name AS ProductName
,a.ListPrice
,a.Color
,b.Name AS ProductSubcategory
,d.ThumbNailPhoto
,d.LargePhoto
FROM Production.Product a
INNER JOIN Production.ProductSubcategory b ON a.ProductSubcategoryID = b.ProductSubcategoryID
INNER JOIN Production.ProductProductPhoto c ON a.ProductID = c.ProductID
INNER JOIN Production.ProductPhoto d ON c.ProductPhotoID = d.ProductPhotoID
WHERE b.ProductCategoryID = 1 -- Bikes
ORDER BY ProductSubcategory, ProductName, a.Color
SET STATISTICS IO OFF
GO
Ini akan menampilkan 97 sepeda dengan gambar. Mereka sangat sulit untuk dijelajahi di perangkat seluler.
ANALISIS
GUNAKAN KONDISI MINIMAL WHERE TANPA OFFSET/FETCH
Inilah berapa banyak pembacaan logis yang diperlukan untuk mengambil 97 produk dengan gambar. Lihat Gambar 5.
Gambar 5 . Pembacaan logis dan pembacaan logika lob saat menggunakan ORDER BY tanpa OFFSET/FETCH dan dengan kondisi WHERE minimal . (Catatan:statistikparser.com tidak menunjukkan pembacaan logika lob. Tangkapan layar diedit berdasarkan hasil di SSMS)
667 pembacaan logis lob muncul karena mengambil gambar dalam 2 kolom. Sementara itu, 590 pembacaan logis digunakan untuk sisanya.
Berikut rencana eksekusi pada Gambar 6 agar nanti bisa kita bandingkan dengan rencana yang lebih baik.
Gambar 6 . Rencana eksekusi menggunakan ORDER BY tanpa OFFSET/FETCH dan dengan kondisi WHERE minimal.
Tidak banyak yang bisa dikatakan sampai kita melihat rencana eksekusi lainnya.
MENGUNAKAN KONDISI MANA TAMBAHAN DAN OFFSET/FETCH DIORDER MENURUT
Sekarang, mari sesuaikan kueri untuk memastikan data minimal dikembalikan. Inilah yang akan kita lakukan:
- Tambahkan kondisi pada subkategori produk. Dalam aplikasi panggilan, kita dapat membayangkan membiarkan pengguna memilih subkategori juga.
- Kemudian, hapus subkategori produk dalam daftar kolom SELECT dan daftar kolom ORDER BY.
- Terakhir, tambahkan OFFSET/FETCH di ORDER BY. Hanya 10 produk yang akan dikembalikan dan ditampilkan di aplikasi panggilan.
Ini kode yang sudah diedit.
DECLARE @pageNumber TINYINT = 1
DECLARE @noOfRows TINYINT = 10 -- each page will display 10 products at a time
SELECT
a.ProductID
,a.Name AS ProductName
,a.ListPrice
,a.Color
,d.ThumbNailPhoto
FROM Production.Product a
INNER JOIN Production.ProductSubcategory b ON a.ProductSubcategoryID = b.ProductSubcategoryID
INNER JOIN Production.ProductProductPhoto c ON a.ProductID = c.ProductID
INNER JOIN Production.ProductPhoto d ON c.ProductPhotoID = d.ProductPhotoID
WHERE b.ProductCategoryID = 1 -- Bikes
AND a.ProductSubcategoryID = 2 -- Road Bikes
ORDER BY ProductName, a.Color
OFFSET (@pageNumber-1)*@noOfRows ROWS FETCH NEXT @noOfRows ROWS ONLY
Kode ini akan meningkat lebih lanjut jika Anda membuatnya menjadi prosedur tersimpan. Ini juga akan memiliki parameter seperti nomor halaman dan jumlah baris. Nomor halaman menunjukkan halaman apa yang sedang dilihat pengguna. Tingkatkan ini lebih jauh dengan membuat jumlah baris fleksibel tergantung pada resolusi layar. Tapi itu cerita lain.
Sekarang, mari kita lihat pembacaan logis pada Gambar 7.
Gambar 7 . Lebih sedikit pembacaan logis setelah menyederhanakan kueri. OFFSET/FETCH juga digunakan dalam ORDER BY.
Kemudian, bandingkan Gambar 7 dengan Gambar 5. Pembacaan logika lob hilang. Selain itu, pembacaan logis mengalami penurunan yang signifikan karena kumpulan hasil juga berkurang dari 97 menjadi 10.
Tapi apa yang dilakukan SQL Server di balik layar? Lihat rencana eksekusi pada Gambar 8.
Gambar 8 . Rencana eksekusi yang lebih sederhana setelah menyederhanakan kueri dan menambahkan OFFSET/FETCH di ORDER BY.
Kemudian, bandingkan Gambar 8 dengan Gambar 6. Tanpa memeriksa setiap operator, kita dapat melihat bahwa rencana baru ini lebih sederhana dari yang sebelumnya.
Pelajaran? Sederhanakan kueri Anda. Gunakan OFFSET/FETCH bila memungkinkan.
Jangan di SQL ORDER BY
Kami sudah selesai dengan apa yang perlu kami lakukan saat menggunakan ORDER BY. Kali ini, mari kita fokus pada apa yang harus kita hindari.
3. Jangan Gunakan ORDER BY Saat Mengurutkan berdasarkan Kunci Indeks Berkelompok
Karena tidak ada gunanya.
Mari kita tunjukkan dengan sebuah contoh.
SET STATISTICS IO ON
GO
-- Using ORDER BY with BusinessEntityID - the primary key
SELECT TOP 100 * FROM Person.Person
ORDER BY BusinessEntityID;
-- Without using ORDER BY at all
SELECT TOP 100 * FROM Person.Person;
SET STATISTICS IO OFF
GO
Kemudian, mari kita periksa pembacaan logis dari kedua pernyataan SELECT pada Gambar 9.
Gambar 9 . 2 kueri pada tabel Person menunjukkan pembacaan logis yang sama. Satu dengan ORDER BY, satu lagi tanpa.
Keduanya memiliki 17 pembacaan logis. Ini logis karena 100 baris yang sama dikembalikan. Tapi apakah mereka memiliki rencana yang sama? Lihat Gambar 10.
Gambar 10 . Paket yang sama apakah ORDER BY digunakan atau tidak saat mengurutkan berdasarkan kunci indeks yang dikelompokkan.
Amati operator yang sama dan biaya kueri yang sama.
Tapi kenapa? Saat mengindeks satu atau lebih kolom ke dalam indeks berkerumun, tabel akan diurutkan secara fisik oleh kunci indeks berkerumun. Jadi, meskipun Anda tidak mengurutkan berdasarkan kunci tersebut, hasilnya akan tetap diurutkan.
Intinya? Maafkan diri Anda dengan tidak menggunakan kunci indeks berkerumun dalam kasus serupa menggunakan ORDER BY . Hemat energi Anda dengan lebih sedikit penekanan tombol.
4. Jangan Gunakan ORDER BY Saat Kolom String Berisi Angka
Jika Anda mengurutkan menurut kolom string yang berisi angka, jangan berharap urutan pengurutan seperti tipe bilangan real. Jika tidak, Anda akan mendapat kejutan besar.
Ini contohnya.
SELECT
NationalIDNumber
,JobTitle
,HireDate
FROM HumanResources.Employee
ORDER BY NationalIDNumber;
Periksa output pada Gambar 11.
Gambar 11 . Urutkan urutan kolom string yang berisi angka. Nilai numerik tidak diikuti.
Pada Gambar 11, urutan leksikografis diikuti. Jadi, untuk memperbaikinya, gunakan CAST ke bilangan bulat.
SELECT
NationalIDNumber
,JobTitle
,HireDate
FROM HumanResources.Employee
ORDER BY CAST(NationalIDNumber AS INT)
Lihat Gambar 12 untuk keluaran tetap.
Gambar 12 . CAST ke INT memperbaiki pengurutan kolom string yang berisi angka.
Jadi, sayadaripada ORDER BY
5. Jangan Gunakan SELECT INTO #TempTable dengan ORDER BY
Urutan sortir yang Anda inginkan tidak akan dijamin di tabel sementara target. Lihat dokumentasi resmi .
Mari kita modifikasi kode dari contoh sebelumnya.
SELECT
NationalIDNumber
,JobTitle
,HireDate
INTO #temp
FROM HumanResources.Employee
ORDER BY CAST(NationalIDNumber AS INT);
SELECT * FROM #temp;
Satu-satunya perbedaan dari contoh sebelumnya adalah klausa INTO. Outputnya akan sama seperti pada Gambar 11. Kami kembali ke kotak 1 bahkan jika kami CAST kolom ke INT.
Anda perlu membuat tabel sementara menggunakan CREATE TABLE. Tetapi sertakan kolom identitas tambahan dan jadikan itu sebagai kunci utama. Kemudian, INSERT ke tabel sementara.
Ini kode tetapnya.
CREATE TABLE #temp2
(
id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
NationalIDNumber NVARCHAR(15) NOT NULL,
JobTitle NVARCHAR(50) NOT NULL,
HireDate DATE NOT NULL
)
GO
INSERT INTO #temp2
(NationalIDNumber, JobTitle, HireDate)
SELECT
NationalIDNumber
,JobTitle
,HireDate
FROM HumanResources.Employee
ORDER BY CAST(NationalIDNumber AS INT);
SELECT
NationalIDNumber
,JobTitle
,HireDate
FROM #Temp2;
Dan hasilnya akan sama seperti pada Gambar 12. Berhasil!
Ingat dalam Menggunakan SQL ORDER BY
Kami telah membahas perangkap umum dalam menggunakan SQL ORDER BY. Berikut ringkasannya:
Lakukan :
- Indeks kolom ORDER BY,
- Batasi hasil dengan WHERE dan OFFSET/FETCH,
Jangan :
- Jangan gunakan ORDER BY saat mengurutkan berdasarkan kunci indeks berkerumun,
- Jangan gunakan ORDER BY jika kolom string berisi angka. Sebagai gantinya, CAST kolom string ke INT terlebih dahulu.
- Jangan gunakan SELECT INTO #TempTable dengan ORDER BY. Sebagai gantinya, buat tabel sementara terlebih dahulu dengan kolom identitas tambahan.
Apa tips dan trik Anda dalam menggunakan ORDER BY? Beri tahu kami di bagian Komentar di bawah. Dan jika Anda menyukai postingan ini, silakan bagikan ke platform media sosial favorit Anda.