Apakah Foreign Key meningkatkan kinerja kueri?

149

Misalkan saya punya 2 tabel, Produk dan Kategori Produk. Kedua tabel memiliki hubungan di CategoryId. Dan ini adalah kueri.

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category
FROM Products p
INNER JOIN ProductCategories c ON p.CategoryId = c.CategoryId
WHERE c.CategoryId = 1;

Ketika saya membuat rencana eksekusi, tabel ProductCategories melakukan pencarian indeks kluster, yang sesuai harapan. Tetapi untuk tabel Produk, ia melakukan scan indeks cluster, yang membuat saya ragu. Mengapa FK tidak membantu meningkatkan kinerja kueri?

Jadi saya harus membuat indeks di Products.CategoryId. Ketika saya membuat rencana eksekusi lagi, kedua tabel melakukan pencarian indeks. Dan diperkirakan biaya subtree berkurang banyak.

Pertanyaan saya adalah:

  1. Selain FK membantu dalam kendala hubungan, apakah ada manfaat lain? Apakah ini meningkatkan kinerja permintaan?

  2. Haruskah saya membuat indeks pada semua kolom FK (disukai Products.CategoryId) di semua tabel?

Chaowlert Chaisrichalermpol
sumber

Jawaban:

186

Kunci Asing adalah alat integritas referensial, bukan alat kinerja. Setidaknya dalam SQL Server, pembuatan FK tidak membuat indeks terkait, dan Anda harus membuat indeks pada semua bidang FK untuk meningkatkan waktu pencarian.

cmsjr
sumber
40
Model yang baik (umumnya) berkinerja lebih baik.
Kenny Evitt
10
"Kunci Asing adalah alat integritas relasional" - silakan gunakan kata 'relasional' dengan hati-hati. Kunci asing adalah konsep basis data, kependekan dari batasan integritas referensial. Mereka bukan bagian dari model relasional. Saya berasumsi Anda membuat kesalahan ketik.
onedaywhen
7
@ Kenny Seringkali ya, tapi kadang model yang lebih baik harganya lebih mahal. Contoh kasus: kunci asing menyebabkan lebih banyak pemrosesan terjadi, tidak kurang.
Hans
8
kunci asing memang meningkatkan kinerja, setidaknya di MySQL. Selain itu, Anda benar, pembuatan FK tidak membuat indeks; pembuatan FK membutuhkan indeks
Félix Gagnon-Grenier
15
Jawaban ini sangat tidak berguna karena tidak menjawab pertanyaan. Sangat menyenangkan mengetahui bahwa kunci asing tidak dimaksudkan untuk memiliki efek (positif) pada kinerja, tetapi pertanyaannya adalah mengenai kenyataan, bukan niat.
John
58

Kunci Asing dapat meningkatkan (dan melukai) kinerja

  1. Seperti yang dinyatakan di sini: Kunci asing meningkatkan kinerja

  2. Anda harus selalu membuat indeks pada kolom FK untuk mengurangi pencarian. SQL Server tidak melakukan ini secara otomatis.

Edit

Karena tautan sekarang tampaknya sudah mati (pujian kepada Chris karena memperhatikan) , berikut ini menunjukkan inti mengapa kunci asing dapat meningkatkan (dan melukai) kinerja.

Bisakah kunci Asing meningkatkan kinerja

Batasan kunci asing meningkatkan kinerja pada saat membaca data tetapi pada saat yang sama memperlambat kinerja pada saat memasukkan / memodifikasi / menghapus data.

Dalam hal membaca kueri, pengoptimal dapat menggunakan batasan kunci asing untuk membuat rencana permintaan yang lebih efisien karena batasan kunci asing adalah aturan yang dinyatakan sebelumnya. Ini biasanya melibatkan melewatkan beberapa bagian dari rencana kueri karena misalnya pengoptimal dapat melihat bahwa karena batasan kunci asing, tidak perlu untuk mengeksekusi bagian tertentu dari rencana tersebut.

Letnan Keersmaekers
sumber
3
Berikut ini tautan yang merinci cara mereka dapat menurunkan kinerja devx.com/getHelpOn/10MinuteSolution/16595/0/page/2
cmsjr
3
Itu masuk akal tetapi Anda hanya akan mengalami ini dengan pernyataan penghapusan besar-besaran. Mungkin kesimpulannya adalah bahwa di lingkungan OLAP, FK yang tidak diindeks akan meningkatkan kinerja sementara di lingkungan OLTP, itu akan menurunkan kinerja.
Lieven Keersmaekers
1
Tautan dalam Jawaban ini sudah mati. Ini sangat disayangkan karena ini satu-satunya argumen di sini untuk meningkatkan kinerja FK.
Chris Moschini
1
@ChrisMoschini - Saya tidak melihat komentar Anda sampai sekarang. Seperti yang telah Anda sebutkan, tautannya sudah mati tetapi intinya disebutkan di tautan baru (dengan perincian) yang saya posting.
Lieven Keersmaekers
2
Tautan Wayback Machine untuk Menang! Artikel ini juga dapat ditemukan di SQLMag.com, di sini .
John Eisbrener
15

Kunci asing adalah konsep DBMS untuk memastikan integritas basis data.

Setiap implikasi / peningkatan kinerja akan spesifik untuk teknologi database yang digunakan dan sekunder untuk tujuan kunci asing.

Ini adalah praktik yang baik dalam SQL Server untuk memastikan bahwa semua kunci asing setidaknya memiliki indeks non-cluster.

Saya harap ini menjelaskan semuanya untuk Anda tetapi jangan ragu untuk meminta detail lebih lanjut.

John Sansom
sumber
9
@Kenny Evitt jika Anda tidak memiliki integritas, data Anda tidak berguna. Saya menemukan bahwa menjual sangat mudah.
HLGEM
@HLGEM Mendapatkan kesalahan 404 sesekali masih cukup tertahankan. Memiliki throughput yang luar biasa sebagai imbalannya menggunakan sumber daya yang lebih murah dan sistem yang tidak terlalu rumit, sekarang juga menjual dengan sangat mudah. Anda mungkin tertarik dengan teorema CAP .
Daniel Dinnyes
8
@Daniel Dinnyes, integritas data bukan tentang mendapatkan kesalahan 404. Ini tentang memiliki data yang dapat digunakan. Ini tentang tidak kehilangan pesanan dan data keuangan untuk laporan misalnya karena ketidakmampuan pengembang. Tidak ada alasan untuk tidak menggunakan kunci asing.
HLGEM
2
Saya setuju dengan HLGEM. Membiarkan kode Anda untuk menangani integritas tidak selalu merupakan ide yang baik. Data sering digunakan untuk mengambil keputusan, tetapi jika datanya rusak, maka keputusan itu tidak akan akurat.
lepe
1
"Kunci Asing adalah alat integritas relasional" - silakan gunakan kata 'relasional' dengan hati-hati. Kunci asing adalah konsep basis data, kependekan dari batasan integritas referensial. Mereka bukan bagian dari model relasional. Saya berasumsi Anda membuat kesalahan ketik.
onedaywhen
4

Taruhan performa terbaik Anda adalah dengan menggunakan Indeks pada bidang yang sering Anda gunakan. Jika Anda menggunakan SQL Server, Anda dapat menggunakan profiler untuk membuat profil basis data tertentu dan mengambil file yang di-output dan menggunakan penyetelan penyetelan untuk menerima rekomendasi tempat menempatkan indeks Anda. Saya juga suka menggunakan profiler untuk membersihkan prosedur tersimpan yang sudah berjalan lama, saya memiliki sepuluh daftar pelaku terburuk yang saya terbitkan setiap minggu, membuat orang jujur: D.

Al Katawazi
sumber
3

Anda dapat menggunakannya untuk membantu membuat kueri lebih efisien. Itu memungkinkan Anda untuk merestrukturisasi permintaan dalam SQL Server untuk menggunakan gabungan luar daripada yang dalam yang menghapus sql server necesity karena harus memeriksa apakah ada nol di kolom. Anda tidak perlu memasukkan kualifikasi itu karena hubungan kunci asing sudah memasukkan itu untuk Anda.

Jadi ini:

    select p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
from Products p inner join ProductCategories c on p.CategoryId = c.CategoryIdwhere c.CategoryId = 1;

Menjadi ini:

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
FROM ProductCategories c 
LEFT OUTER JOIN Products P ON
c.CategoryId = p.CategoryId 
WHERE c.CategoryId = 1;

Ini tidak harus membuat kinerja besar dalam kueri kecil, tetapi ketika tabel menjadi besar itu bisa lebih efisien.

kemiller2002
sumber
3
Tidak hanya gabungan luar biasanya kurang efisien daripada gabungan dalam ( stackoverflow.com/a/2726683/155892 ), sekarang pertanyaan Anda menyesatkan: Anda mengandalkan database untuk secara implisit mengubah sambungan luar Anda menjadi gabungan batin (memulihkan kinerja) bukannya hanya melakukan itu secara eksplisit
Mark Sowul
2

Untuk MySQL 5.7, itu pasti dapat mempercepat permintaan yang melibatkan banyak gabungan dengan sangat baik!

Saya menggunakan 'jelaskan' untuk memahami permintaan saya dan menemukan bahwa saya bergabung dengan 4-5 tabel - di mana tidak ada kunci yang digunakan sama sekali. Saya tidak melakukan apa pun selain menambahkan kunci asing ke tabel ini dan hasilnya adalah pengurangan 90% pada waktu buka. Kueri yang membutuhkan> 5s sekarang membutuhkan 500ms atau kurang.

Itu adalah peningkatan BESAR!

DAN, seperti yang disebutkan orang lain, Anda mendapatkan bonus tambahan untuk memastikan integritas relasional.

Selain itu, memastikan integritas referensial memiliki manfaat kinerja sendiri. Ini memiliki efek urutan kedua untuk memastikan bahwa tabel yang memiliki kunci asing 'terkini' dengan tabel asing. Katakanlah Anda memiliki tabel pengguna dan tabel komentar, dan Anda melakukan beberapa statistik pada tabel komentar. Mungkin jika Anda sulit menghapus pengguna, Anda tidak ingin komentar mereka lagi.

Peter Bartlett
sumber
Apakah tabel memiliki indeks yang diperlukan untuk menghasilkan kunci asing sebelum Anda menambahkannya?
George
1

Menambahkan kunci asing dalam tabel tidak akan meningkatkan kinerja, hanya mengatakan jika Anda memasukkan catatan dalam basis data tabel ProductCategories akan mencoba menemukan kolom kunci asing memiliki nilai yang ada di nilai kunci utama tabel produk, ini terlihat, operasi adalah overhead pada database Anda setiap kali Anda menambahkan entri baru di tabel ProductCategories. Jadi dengan menambahkan kunci asing tidak akan meningkatkan kinerja basis data Anda tetapi akan menjaga integritas basis data Anda. Ya itu akan meningkatkan kinerja Anda db jika Anda memeriksa integritas menggunakan kunci asing alih-alih menjalankan banyak pertanyaan untuk memeriksa catatan ada di database dalam program Anda.

Pankaj Khairnar
sumber
0

Saya tidak tahu banyak tentang SQL server, tetapi dalam kasus Oracle, memiliki kolom kunci asing mengurangi kinerja pemuatan data. Itu karena database perlu memeriksa integritas data untuk setiap sisipan. Dan ya, seperti yang telah disebutkan, memiliki indeks pada kolom kunci asing adalah praktik yang baik.

Shamik
sumber