Saat Anda memiliki kueri atau prosedur tersimpan yang membutuhkan penyetelan kinerja, apa saja hal pertama yang Anda coba?
Saat Anda memiliki kueri atau prosedur tersimpan yang membutuhkan penyetelan kinerja, apa saja hal pertama yang Anda coba?
Jawaban:
Berikut adalah daftar berguna yang selalu saya berikan kepada seseorang yang bertanya kepada saya tentang pengoptimalan.
Kami terutama menggunakan Sybase, tetapi sebagian besar saran akan berlaku di seluruh papan.
SQL Server, misalnya, dilengkapi dengan sejumlah bit pemantauan / penyetelan kinerja, tetapi jika Anda tidak memiliki yang seperti itu (dan mungkin bahkan jika Anda melakukannya) maka saya akan mempertimbangkan yang berikut ...
99% masalah yang saya lihat disebabkan oleh menempatkan terlalu banyak tabel dalam suatu gabungan . Perbaikan untuk ini adalah dengan melakukan setengah dari gabungan (dengan beberapa tabel) dan menyimpan hasilnya dalam tabel sementara. Kemudian lakukan sisa kueri yang bergabung di tabel sementara itu.
#temptabel mungkin berkinerja lebih baik daripada @tablevariabel dengan volume besar (ribuan baris).Agak topik, tetapi jika Anda memiliki kontrol atas masalah ini ...
Tingkat tinggi dan Dampak Tinggi
CREATE INDEX
Yakinkan ada indeks yang tersedia untuk Anda WHEREdan JOINklausa. Ini akan sangat mempercepat akses data.
Jika lingkungan Anda adalah data mart atau gudang, indeks harus berlimpah untuk hampir semua permintaan yang mungkin.
Dalam lingkungan transaksional , jumlah indeks harus lebih rendah dan definisinya lebih strategis sehingga pemeliharaan indeks tidak menurunkan sumber daya. (Pemeliharaan indeks adalah ketika daun indeks harus diubah untuk mencerminkan perubahan dalam tabel yang mendasarinya, seperti dengan INSERT, UPDATE,dan DELETEoperasi.)
Selain itu, perhatikan urutan bidang dalam indeks - bidang yang lebih selektif (kardinalitas lebih tinggi), yang lebih awal dalam indeks akan muncul. Misalnya, Anda meminta mobil bekas:
SELECT i.make, i.model, i.price
FROM dbo.inventory i
WHERE i.color = 'red'
AND i.price BETWEEN 15000 AND 18000
Harga umumnya memiliki kardinalitas yang lebih tinggi. Mungkin hanya ada beberapa lusin warna yang tersedia, tetapi sangat mungkin ribuan harga yang diminta berbeda.
Dari pilihan indeks ini, idx01berikan jalur yang lebih cepat untuk memenuhi kueri:
CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)
Ini karena lebih sedikit mobil yang akan memenuhi titik harga daripada pilihan warna, memberikan mesin kueri data yang jauh lebih sedikit untuk dianalisis.
Saya dikenal memiliki dua indeks yang sangat mirip, hanya berbeda di bidang untuk mempercepat kueri (nama depan, nama belakang) dalam satu dan (nama belakang, nama depan) di yang lain.
Trik yang baru-baru ini saya pelajari adalah bahwa SQL Server dapat memperbarui variabel lokal serta bidang, dalam pernyataan pembaruan.
UPDATE table
SET @variable = column = @variable + otherColumn
Atau versi yang lebih mudah dibaca:
UPDATE table
SET
@variable = @variable + otherColumn,
column = @variable
Saya telah menggunakan ini untuk mengganti kursor / gabungan yang rumit ketika menerapkan perhitungan rekursif, dan juga mendapatkan banyak kinerja.
Berikut detail dan contoh kode yang membuat peningkatan fantastis dalam kinerja: http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal. aspx
Dengan asumsi MySQL di sini, gunakan EXPLAIN untuk mencari tahu apa yang terjadi dengan kueri, pastikan bahwa indeks digunakan seefisien mungkin dan mencoba untuk menghilangkan jenis file. MySQL Berkinerja Tinggi: Optimasi, Cadangan, Replikasi, dan Lainnya adalah buku yang hebat tentang topik ini seperti halnya Blog Kinerja MySQL .
@Terrapin ada beberapa perbedaan lain antara isnull dan penggabungan yang layak disebutkan (selain kepatuhan ANSI, yang merupakan hal besar bagi saya).
Terkadang dalam SQL Server jika Anda menggunakan ATAU di mana klausa itu benar-benar akan mendongkrak kinerja. Alih-alih menggunakan ATAU, lakukan saja dua pemilihan dan satukan keduanya. Anda mendapatkan hasil yang sama dengan kecepatan 1000x.
Saya biasanya akan mulai dengan gabungan - saya akan mengetuk masing-masing dari kueri satu per satu dan menjalankan kembali kueri untuk mendapatkan ide jika ada gabung tertentu yang bermasalah dengan saya.
Pada semua tabel temp saya, saya ingin menambahkan batasan unik (jika perlu) untuk membuat indeks, dan kunci utama (hampir selalu).
declare @temp table(
RowID int not null identity(1,1) primary key,
SomeUniqueColumn varchar(25) not null,
SomeNotUniqueColumn varchar(50) null,
unique(SomeUniqueColumn)
)
Saya sudah terbiasa untuk selalu menggunakan variabel bind. Mungkin variabel terikat tidak akan membantu jika RDBMS tidak men-cache pernyataan SQL. Tetapi jika Anda tidak menggunakan variabel bind, RDBMS tidak memiliki kesempatan untuk menggunakan kembali rencana eksekusi permintaan dan menguraikan pernyataan SQL. Penghematan bisa sangat besar: http://www.akadia.com/services/ora_bind_variables.html . Saya bekerja sebagian besar dengan Oracle, tetapi Microsoft SQL Server bekerja dengan cara yang hampir sama.
Dalam pengalaman saya, jika Anda tidak tahu apakah Anda menggunakan variabel mengikat atau tidak, Anda mungkin tidak. Jika bahasa aplikasi Anda tidak mendukungnya, temukan yang mendukung. Terkadang Anda dapat memperbaiki kueri A dengan menggunakan variabel bind untuk kueri B.
Setelah itu, saya berbicara dengan DBA kami untuk mencari tahu apa yang paling menyebabkan rasa sakit pada RDBMS. Perhatikan bahwa Anda seharusnya tidak bertanya "Mengapa permintaan ini lambat?" Itu seperti meminta dokter Anda untuk mengambil Anda lampiran. Tentu kueri Anda mungkin masalahnya, tetapi kemungkinan besar ada sesuatu yang salah. Sebagai pengembang, kami cenderung berpikir dalam hal baris kode. Jika saluran lambat, perbaiki jalur itu. Tetapi RDBMS adalah sistem yang sangat rumit dan permintaan Anda yang lambat mungkin merupakan gejala dari masalah yang jauh lebih besar.
Terlalu banyak tips tuning SQL adalah berhala pemujaan kargo. Sebagian besar masalah tidak terkait atau minimal terkait dengan sintaks yang Anda gunakan, jadi biasanya yang terbaik adalah menggunakan sintaks terbersih yang Anda bisa. Kemudian Anda bisa mulai mencari cara untuk menyempurnakan basis data (bukan kueri). Hanya men-tweak sintaks ketika itu gagal.
Seperti penyetelan kinerja, selalu kumpulkan statistik yang berarti. Jangan gunakan waktu jam dinding kecuali itu adalah pengalaman pengguna yang sedang Anda setel. Alih-alih melihat hal-hal seperti waktu CPU, baris diambil dan blok pembacaan disk. Terlalu sering orang mengoptimalkan untuk hal yang salah.
Menjalankan kueri menggunakan WITH (NoLock) cukup banyak operasi standar di tempat saya. Siapa pun yang ketahuan menjalankan kueri pada tabel puluhan gigabytes tanpa dikeluarkan dan ditembak.
Konversikan BUKAN kueri menjadi LEFT OUTER GABUNG jika memungkinkan. Misalnya jika Anda ingin menemukan semua baris di Table1 yang tidak digunakan oleh kunci asing di Table2 Anda bisa melakukan ini:
SELECT *
FROM Table1
WHERE Table1.ID NOT IN (
SELECT Table1ID
FROM Table2)
Tetapi Anda mendapatkan kinerja yang jauh lebih baik dengan ini:
SELECT Table1.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.Table1ID
WHERE Table2.ID is null
Tidak harus trik kinerja SQL per se tetapi pasti terkait:
Sebaiknya gunakan memcached jika mungkin karena akan jauh lebih cepat hanya dengan mengambil data yang sudah dikompilasi langsung dari memori daripada mendapatkannya dari database. Ada juga rasa MySQL yang memcached built in (pihak ketiga).
Pastikan panjang indeks Anda sekecil mungkin. Ini memungkinkan DB untuk membaca lebih banyak kunci sekaligus dari sistem file, sehingga mempercepat penggabungan Anda. Saya menganggap ini bekerja dengan semua DB, tapi saya tahu ini adalah rekomendasi khusus untuk MySQL.
Saya mencari:
SET NOCOUNT ON
Biasanya baris pertama di dalam prosedur tersimpan saya, kecuali saya benar-benar perlu menggunakan @@ROWCOUNT.
Dalam SQL Server, gunakan direktif nolock. Ini memungkinkan perintah pilih untuk selesai tanpa harus menunggu - biasanya transaksi lainnya selesai.
SELECT * FROM Orders (nolock) where UserName = 'momma'
Hapus panggilan fungsi di Sprocs di mana banyak baris akan memanggil fungsi.
Kolega saya menggunakan panggilan fungsi (dapatkan lastlogindate dari userid sebagai contoh) untuk mengembalikan recordset yang sangat luas.
Ditugasi dengan pengoptimalan, saya mengganti pemanggilan fungsi dalam sproc dengan kode fungsi: Saya mendapatkan banyak waktu sprocs 'berjalan dari> 20 detik menjadi <1.
Saya suka menggunakan
isnull(SomeColThatMayBeNull, '')
Lebih
coalesce(SomeColThatMayBeNull, '')
Ketika saya tidak membutuhkan dukungan banyak argumen yang menyatu memberi Anda.
http://blog.falafel.com/2006/04/05/SQLServerArcanaISNULLVsCOALESCE.aspx
Jangan awali nama Prosedur Tersimpan dengan "sp_" karena semua prosedur sistem dimulai dengan "sp_", dan SQL Server harus mencari lebih keras untuk menemukan prosedur Anda ketika dipanggil.
set transaction isolation level read uncommitted
Mencegah kunci mati di mana integritas transaksional tidak mutlak diperlukan (yang biasanya benar)
Saya selalu pergi ke SQL Profiler (jika ini adalah prosedur tersimpan dengan banyak tingkat bersarang) atau perencana pelaksanaan kueri (jika itu beberapa pernyataan SQL tanpa bersarang) terlebih dahulu. 90% dari waktu Anda dapat segera menemukan masalah dengan salah satu dari dua alat ini.