Yabancı anahtarları nerede tanımlamalısınız?


Yanıtlar:


41

Yabancı anahtarları veritabanına yerleştirin. Uygulamadaki verileri kaydetmeden önce doğrulasanız bile, FK'ler iyi bir QA yedeklemesidir. İlk yaklaşım için, uygulamaların her zaman veri sorunları vardır. Bu gibi kontrolleri sistemden çıkarmak, sadece verilerin sessizce bozulduğu arıza modlarını davet eder.

Bunu gerçekleştirmek için birkaç yıl veri ambarında çalışmak gibisi yoktur. Zamanınızı, uygulama kodunda veri bütünlüğünü uygulayabileceklerini düşünen uygulama geliştiricileri tarafından baştan başa hataların ardından parçaları almaya harcarsınız. Bunu yapmak için zaman harcayın; uygulama yönetilen veri bütünlüğünün bir kuraldan çok daha fazlası olmadığı sonucuna varacaksınız.

Ek olarak, sorgu optimizatörü, masa birleşmeleri hakkında bir şeyler çıkarmak için yabancı anahtarları kullanabilir, böylece FK'ler daha verimli sorgu planları ile sonuçlanacaktır.

Yabancı anahtarların da birçok yararı var. Herkese bir iyilik yap - FK'leri veritabanına koy.


15

Referans Bütünlüğü, asıl veri tabanı olan mümkün olan en düşük seviyede ele alınmalıdır. İlişkisel Veri Tabanı Yönetim Sistemleri bunun üstesinden gelmek için optimize edilmiştir. Atasöz tekerleği yeniden icat etmek mantıklı değil.

DML deyiminin bir RI istisnasına neden olmasını önlemek için uygulama kodunda etki alanı mantığını tanımlamak kabul edilebilir, ancak bu, veritabanındaki yabancı anahtar ilişkilerinin yerine kullanılmamalıdır.


12

DBA odaklı bir grup olduğu için buranın tamamen oy kullanmasını bekliyorum.

Sıkı yabancı anahtar kullanmanın çoğu senaryoda en iyi karar olduğuna katılıyorum. Ancak, yabancı anahtarların çözdüklerinden daha fazla soruna neden olduğu bazı durumlar vardır.

Yüksek trafikli web uygulaması gibi çok eşzamanlı bir ortamla uğraşıyorsanız ve sağlam, sağlam bir ORM kullanıyorsanız, yabancı anahtarlar ölçeklendirmeyi ve sunucuyu zorlaştırmayı sağlayan kilitleme sorunlarına neden olabilir. Alt tablodaki satırları güncellerken, ana satır da kilitlenir. Birçok senaryoda, bu kilitleme çekişmesi nedeniyle eşzamanlılığı ciddi şekilde sınırlayabilir. Ek olarak, bazen (en azından geçici olarak) referans bütünlüğü kurallarını (kasıtlı olarak) kırmanız gerekebilecek arşiv işlemleri gibi ayrı ayrı tablolarda bakım yapmanız gerekir. Yabancı anahtarlar takılıyken, bu inanılmaz zor olabilir ve bazı RDBMS'lerde yabancı anahtar kısıtlamalarını devre dışı bırakmak, önemli ölçüde kesinti gerektiren bir zaman alıcı süreç olan tablonun yeniden oluşturulmasına neden olur.

Veritabanının dışındaki referans bütünlüğünü anlayabilen sağlam bir çerçeve kullanmanız gerektiğine dair ihtarı dahil ettiğimi anlayın. Yine de, bazı referans bütünlük sorunları ile sonuçlanacak. Ancak, artık yetim sıraları ya da küçük referans bütünlüğü ihlalleri olması büyük bir mesele değildir. Web uygulamalarının çoğunun bu kategoriye girdiğini iddia ediyorum.

Olduğu söyleniyor, kimse Facebook olarak başlıyor. Veritabanınızdaki yabancı anahtarları tanımlayarak başlayın. İzleyin. Eğer sorun yaşarsanız, ölçeklendirmek için bu kısıtlamaları bırakmanız gerekebileceğini anlayın.

Sonuç olarak: Çoğu veritabanında yabancı anahtarlar olmalıdır. Yüksek eşzamanlı ortamlar yabancı anahtarlar olmadan daha iyi olabilir. Bu noktaya ulaşırsanız, bu kısıtlamaları bırakmayı düşünmeniz gerekebilir.

Alev geciktirici giysimi şimdi giyeceğim.

EDIT 2012-03-23 ​​7:00 AM

Yabancı anahtarların kilitleme sonuçları hakkında düşünürken, sunucu yüküne ek olarak, içsel olarak oluşturulan tüm ek sıra aramalarının maliyetinden bahsetmeyi ihmal ettim.

Sonuçta, benim açımdan yabancı anahtarların ücretsiz olmadığıdır. Çoğu durumda, maliyet buna değer, ancak bu maliyetin faydalarını aştığı senaryolar var.

EDIT 2012-03-23 ​​07:38

Somut olalım. Yabancı anahtar davranışına çok fazla saygı duyulmayan bu örnekte MySQL / InnoDB'yi seçiyorum, ama en çok aşina olduğum şey ve muhtemelen en çok kullanılan web veritabanı. Göstermek üzere olduğum örnekle başka bir veritabanının daha iyi olacağından emin değilim.

Ebeveynine başvuran yabancı anahtarlı bir çocuk tablosu düşünün. Örnek olarak, MySQL'deki sakila örnek veritabanındaki film ve film_actor tablolarına bakın:

CREATE TABLE `film` (
  `film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `description` text,
  `release_year` year(4) DEFAULT NULL,
  `language_id` tinyint(3) unsigned NOT NULL,
  `original_language_id` tinyint(3) unsigned DEFAULT NULL,
  `rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3',
  `rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
  `length` smallint(5) unsigned DEFAULT NULL,
  `replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99',
  `rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G',
  `special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`film_id`),
  KEY `idx_title` (`title`),
  KEY `idx_fk_language_id` (`language_id`),
  KEY `idx_fk_original_language_id` (`original_language_id`),
  CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE,
  CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8

CREATE TABLE `film_actor` (
  `actor_id` smallint(5) unsigned NOT NULL,
  `film_id` smallint(5) unsigned NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`actor_id`,`film_id`),
  KEY `idx_fk_film_id` (`film_id`),
  CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES `actor` (`actor_id`) ON UPDATE CASCADE,
  CONSTRAINT `fk_film_actor_film` FOREIGN KEY (`film_id`) REFERENCES `film` (`film_id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

İlgili kısıtlama benim örneğim için film_actor (fk_film_actor_film).

session1> BEGIN;
session1> INSERT INTO film_actor (actor_id, film_id) VALUES (156, 508);
Query OK, 1 row affected (0.00 sec)

session2> BEGIN;
session2> UPDATE film SET release_year = 2005 WHERE film_id = 508;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Alt tabloya eklerken üst satırdaki alakasız bir alanı güncelleyemediğimi unutmayın. Bu, InnoDB'nin film_actor üzerindeki FK kısıtlaması nedeniyle film.film_id = 508 olduğu sıradaki paylaşılan bir kilidi tutması nedeniyle oluşur, bu nedenle o sıradaki GÜNCELLEME gereken özel kilidi alamaz. Bu işlemi tersine çevirir ve önce GÜNCELLEME çalıştırırsanız, aynı davranışa sahipsiniz ancak INSERT engellenmiştir.

session1> BEGIN;
session1> UPDATE film SET release_year = 2005 WHERE film_id = 508;
Query OK, 1 row affected (0.00 sec)

session2> BEGIN;
session2> INSERT INTO film_actor (actor_id, film_id) VALUES (156, 508);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

usersDüzinelerce ilgili tablonun bulunduğu bir web uygulamasında bir tablo düşünün . Temel olarak, ilgili bir satırdaki herhangi bir işlem üst satırda bir güncelleme yapılmasını önler. Birden fazla yabancı anahtar ilişkiniz ve çok fazla eşzamanlılığınız varsa, bu zor bir problem olabilir.

FK kısıtlamaları, masa bakımı için de geçici çözümler sağlayabilir. Percona'dan Peter Zaitsev'in benden daha iyi açıklayan bir blog yazısı var: Hijacking Innodb Foreign Keys .


Yorumlar uzun tartışmalar için değildir; bu konuşma sohbete taşındı .
Paul White GoFundMonica

6

Yabancı anahtarın veritabanında kullanılması iyi bir uygulamadır. Yardımcı olur-

  • İstenmeyen veri olasılığını ortadan kaldırarak veri bütünlüğünü korumak
  • performansını artırmak için. Otomatik indeks alanlarının bulunduğu sistemlerde yabancı anahtar referansları performans artışı sağlayabilir
  • programcı tarafından daha az kod yazmak için. beğenmek, kullanmakON DELETE CASCADE
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.