Yabancı Anahtar sorgu performansını iyileştirir mi?


149

Diyelim ki 2 tablom var, Ürünler ve Ürün Kategorileri. Her iki tablonun CategoryId üzerinde ilişkisi vardır. Ve bu sorgu.

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;

Yürütme planı oluşturduğumda, ProductCategories tablosu beklenti olarak küme dizin araması gerçekleştirir. Ancak tablo Ürünleri için, beni şüphe uyandıran küme dizin taraması gerçekleştirir. FK neden sorgu performansını artırmaya yardımcı olmuyor?

Bu yüzden Products.CategoryId dizin oluşturmak gerekir. Yeniden yürütme planı oluşturduğumda, her iki tablo da dizin araması yapar. Ve tahmini alt ağaç maliyeti çok azalır.

Sorularım:

  1. FK'nin ilişki kısıtlamasına yardımcı olmasının yanı sıra, başka bir faydası var mı? Sorgu performansını artırıyor mu?

  2. Tüm tablolarda tüm FK sütunlarında dizin oluşturmalı mıyım (Like Products.CategoryId)?

Yanıtlar:


186

Yabancı Anahtarlar bir performans aracı değil, başvuru bütünlüğü aracıdır. En azından SQL Server'da, FK oluşturulması ilişkili bir dizin oluşturmaz ve arama sürelerini iyileştirmek için tüm FK alanlarında dizinler oluşturmanız gerekir.


40
İyi modeller (genellikle) daha iyi performans gösterir.
Kenny Evitt

10
"Yabancı Anahtarlar ilişkisel bütünlük aracıdır" - lütfen 'ilişkisel' kelimesini dikkatli kullanın. Yabancı anahtarlar bir veritabanı kavramıdır, referans bütünlüğü kısıtlaması için kısa eldir. Bunlar ilişkisel modelin bir parçası değildir. Yazım hatası yaptığınızı varsayıyorum.
gün

7
@Kenny Genellikle evet, ancak bazen daha iyi bir model daha pahalıya mal olur. Durumda: yabancı anahtarlar daha az değil, daha fazla işlem yapılmasına neden olur.
Hans

8
yabancı anahtarlar yapmak en azından MySQL, performansını artırmak. Dahası, haklısınız, bir FK oluşturmak bir indeks oluşturmaz; bir FK oluşturulması için bir endeks gereklidir
Félix Gagnon-Grenier

15
Bu cevap neredeyse işe yaramaz çünkü soruyu cevaplamıyor. Yabancı anahtarların performans üzerinde (olumlu) bir etkiye sahip olmalarının amaçlanmadığını bilmek harika , ancak soru gerçeklerle ilgilidir, niyetlerle değil.
John

58

Yabancı Anahtarlar performansı artırabilir (ve incitebilir)

  1. Burada belirtildiği gibi: Yabancı anahtarlar performansı artırır

  2. Aramaları azaltmak için her zaman FK sütunlarında dizinler oluşturmalısınız. SQL Server bunu otomatik olarak yapmaz.

Düzenle

Bağlantı artık ölü gibi göründüğü için (farkedilmek için Chris'e kudos) , aşağıda yabancı anahtarların performansı nasıl artırabileceği (ve incitebileceği) özü gösterilmektedir.

Yabancı anahtar performansı artırabilir mi

Yabancı anahtar kısıtı, veri okuma sırasında performansı artırır, ancak aynı zamanda veri ekleme / değiştirme / silme sırasında performansı yavaşlatır.

Sorgunun okunması durumunda, yabancı anahtar kısıtlamaları önceden bildirilen kurallar olduğundan, daha etkin sorgu planları oluşturmak için optimize edici yabancı anahtar kısıtlamalarını kullanabilir. Bu genellikle sorgu planının bir kısmını atlamayı içerir, çünkü örneğin optimize edici, yabancı anahtar kısıtlaması nedeniyle planın belirli bir bölümünü yürütmenin gereksiz olduğunu görebilir.


3
İşte performansı düşürme yollarını ayrıntılarıyla açıklayan bir bağlantı devx.com/getHelpOn/10MinuteSolution/16595/0/page/2
cmsjr

3
Bu mantıklı, ancak sadece büyük bir silme ifadesi ile karşılaşacaksınız. Belki de sonuç, OLAP ortamlarında, endekslenmemiş FK'lerin OLTP ortamlarında performansı artıracağı, performansı düşüreceği yönündedir.
Lieven Keersmaekers

1
Bu Yanıttaki bağlantı öldü. Bu talihsiz bir durumdur, çünkü burada FK'lerin performansı artıran tek argüman.
Chris Moschini

1
@ChrisMoschini - Yorumunuzu şimdiye kadar fark etmedim. Bahsettiğiniz gibi, bağlantı öldü, ancak yayınladığım yeni bağlantıda (ayrıntılarla) bağlantıdan bahsediliyor.
Lieven Keersmaekers

2
Kazanmak için Wayback Machine bağlantısı ! Makaleyi burada da SQLMag.com adresinde bulabilirsiniz .
John Eisbrener

15

Yabancı anahtar, veritabanı bütünlüğünü sağlamak için DBMS konseptidir.

Tüm performans sonuçları / iyileştirmeler kullanılan veritabanı teknolojisine özgü olacaktır ve yabancı anahtarın amacına ikincil olacaktır.

Tüm yabancı anahtarların üzerinde en azından kümelenmemiş bir dizin olmasını sağlamak SQL Server'da iyi bir uygulamadır.

Umarım bu sizin için bir şeyleri temizler, ancak daha fazla bilgi istemekten çekinmeyin.


9
@Kenny Evitt bütünlüğünüz yoksa verileriniz işe yaramaz. Çok kolay sattığını görüyorum.
HLGEM

@HLGEM Arada bir 404 hatası almak hala oldukça katlanılabilir. Daha ucuz kaynaklar ve daha az karmaşık sistemler kullanarak olağanüstü verim elde etmek, şimdi de çok kolay satıyor. CAP teoremiyle ilgileniyor olabilirsiniz .
Daniel Dinnyes

8
@Daniel Dinnyes, veri bütünlüğü 404 hatası almakla ilgili değil. Kullanılabilir verilere sahip olmakla ilgilidir. Örneğin, geliştiricilerin yetersizliği nedeniyle raporlar için siparişleri ve finansal verileri kaybetmemekle ilgilidir. Yabancı anahtarları kullanmamak için ÖZEL YOKTUR.
HLGEM

2
HLGEM ile hemfikirim. Kodunuzun bütünlüğü ele almasına izin vermek her zaman iyi bir fikir değildir. Veriler genellikle karar almak için kullanılır, ancak veriler bozulursa karar doğru olmayacaktır.
lepe

1
"Yabancı Anahtarlar ilişkisel bütünlük aracıdır" - lütfen 'ilişkisel' kelimesini dikkatli kullanın. Yabancı anahtarlar bir veritabanı kavramıdır, referans bütünlüğü kısıtlaması için kısa eldir. Bunlar ilişkisel modelin bir parçası değildir. Yazım hatası yaptığınızı varsayıyorum.
gün

4

En iyi performans bahsiniz, sık kullandığınız alanlarda Dizinleri kullanmaktır. SQL Server kullanıyorsanız, belirli bir veritabanını profillemek ve çıktıyı alan dosyayı almak için profiler kullanabilirsiniz ve dizinlerinizi nereye yerleştireceğinize ilişkin önerileri almak için ayarlama sihirbazını kullanabilirsiniz. Ayrıca uzun süren saklı yordamları temizlemek için profiler kullanmayı seviyorum, her hafta yayınladığım ilk on kötü suçlunun listesi var, insanları dürüst tutar: D.


3

Bir sorguyu daha verimli hale getirmek için kullanabilirsiniz. SQL Server'da sorguları, sütunta bir boş olup olmadığını kontrol etme zorunluluğu olan sql sunucularını kaldıran bir iç birleşim yerine kullanmak üzere yeniden yapılandırmanıza izin verir. Bu niteleyiciyi koymanıza gerek yok çünkü yabancı anahtar ilişkisi zaten bunu sizin için güçlendiriyor.

Yani bu:

    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;

Bu olur:

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;

Bu, küçük sorgularda mutlaka büyük bir performans sağlamaz, ancak tablolar büyüdüğünde daha verimli olabilir.


3
Dış birleşimler genellikle iç birleşimlere göre daha az verimli olmakla kalmaz ( stackoverflow.com/a/2726683/155892 ), şimdi sorgularınız yanıltıcıdır: dış birleşimlerinizi örtülü olarak iç birleşimlere dönüştürmek için veritabanına güveniyorsunuz (performansı geri yüklüyorsunuz) bunu açıkça yapmak yerine
Mark Sowul

2

MySQL 5.7 için, kesinlikle çok sayıda birleştirmeyi içeren sorguları inanılmaz derecede iyi bir şekilde hızlandırabilir!

Sorgumu anlamak için 'açıklama' kullandım ve hiçbir anahtarın kullanılmadığı 4-5 tabloya katıldığımı gördüm. Bu tablolara yabancı anahtar eklemek dışında hiçbir şey yapmadım ve sonuç yükleme süresinde% 90 azalma oldu. 5 yaşından büyük olan sorgular artık 500ms veya daha az sürüyor.

Bu muazzam bir gelişme!

VE, diğerlerinin de belirttiği gibi, ilişkisel bütünlük sağlamanın ek bonusunu elde edersiniz.

Bunun ötesinde, referans bütünlüğünün sağlanması da kendi performans avantajlarına sahiptir. Yabancı anahtar içeren tabloların yabancı tablo ile 'güncel' olmasını sağlamanın ikinci dereceden etkisi vardır. Bir kullanıcı tablonuz ve yorum tablonuz olduğunu ve yorum tablosunda bazı istatistikler yaptığınızı varsayalım. Muhtemelen kullanıcıyı sert bir şekilde silerseniz, artık yorumlarını da istemezsiniz.


Tablolar, siz eklemeden önce yabancı anahtarları oluşturmak için gerekli dizinlere sahip miydi?
George

1

Tabloya bir yabancı anahtar eklemek performansı artırmayacak, bir ProductCategories tablo veritabanına kayıt ekleyip eklemediğinizi, yabancı anahtar sütununun ürün tablosunun birincil anahtar değerinde var olan bir değere sahip olduğunu bulmaya çalışacağını söyleyerek, işlemi, ProductCategories tablosuna her yeni giriş eklediğinizde veritabanınızda eklenir. Yabancı bir anahtar eklemek veritabanı performansınızı artırmak olmaz ama veritabanınızın bütünlüğü ile ilgilenecektir. Evet, programınızdaki veritabanında kayıt olup olmadığını denetlemek için birçok sorguyu çalıştırmak yerine yabancı anahtar kullanarak bütünlüğü kontrol ediyorsanız, db'nizin performansını artıracaktır.


0

SQL sunucusu hakkında çok şey bilmiyorum, ancak Oracle durumunda, yabancı bir anahtar sütununa sahip olmak veri yükleme performansını azaltır. Bunun nedeni, veritabanının her bir ekleme için veri bütünlüğünü kontrol etmesi gerektiğidir. Ve evet, daha önce de belirtildiği gibi, yabancı anahtar sütununda bir endekse sahip olmak iyi bir uygulamadır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.