Di mana Anda harus mendefinisikan kunci asing?

Jawaban:

41

Letakkan kunci asing di database. Bahkan jika Anda memvalidasi data dalam aplikasi sebelum Anda menyimpannya, FK adalah cadangan QA yang bagus. Untuk perkiraan pertama, aplikasi selalu memiliki masalah data. Membiarkan kontrol seperti ini keluar dari sistem hanya mengundang mode kegagalan di mana data rusak secara diam-diam.

Tidak ada yang seperti bekerja di pergudangan data selama beberapa tahun untuk melihat tindakan ini. Anda menghabiskan waktu untuk mengambil bagian setelah kesalahan besar oleh pengembang aplikasi yang berpikir mereka bisa menegakkan integritas data dalam kode aplikasi. Luangkan waktu untuk melakukan ini dan Anda akan menyimpulkan bahwa integritas data yang dikelola aplikasi sedikit lebih dari kesombongan.

Selain itu, pengoptimal kueri dapat menggunakan kunci asing untuk menyimpulkan hal-hal tentang gabungan tabel, sehingga FK akan menghasilkan rencana kueri yang lebih efisien.

Ada banyak manfaat lain untuk kunci asing juga. Bantu semua orang - letakkan FK di database.

ConcernedOfTunbridgeWells
sumber
15

Integritas Referensial harus ditangani pada tingkat serendah mungkin, yang akan menjadi basis data yang mendasarinya. Sistem Manajemen Basis Data Relasional dioptimalkan untuk menangani hal ini. Tidak masuk akal untuk menemukan kembali roda pepatah.

Dapat diterima untuk mendefinisikan logika domain dalam kode aplikasi untuk mencegah pernyataan DML untuk bahkan menyebabkan pengecualian RI, tetapi ini tidak boleh dilihat sebagai pengganti untuk hubungan kunci asing dalam database.

Thomas Stringer
sumber
12

Saya akan pergi mengambil risiko di sini sepenuhnya mengharapkan ini untuk mendapatkan suara karena ini adalah kelompok yang berfokus pada DBA.

Saya setuju bahwa menggunakan kunci asing yang ketat adalah keputusan terbaik dalam sebagian besar skenario. Namun, ada beberapa kasus di mana kunci asing menyebabkan lebih banyak masalah daripada yang dipecahkan.

Ketika Anda berhadapan dengan lingkungan yang sangat konkuren seperti aplikasi web dengan lalu lintas tinggi, dan menggunakan ORM yang mapan dan kuat, kunci asing dapat menyebabkan masalah penguncian yang membuat penskalaan dan pemeliharaan server menjadi sulit. Saat memperbarui baris dalam tabel anak, baris induk juga dikunci. Dalam banyak skenario, ini dapat secara drastis membatasi konkurensi karena penguncian pertengkaran. Selain itu, kadang-kadang Anda harus melakukan pemeliharaan pada tabel individual, seperti proses pengarsipan di mana Anda mungkin perlu (dengan sengaja) melanggar aturan integritas referensial, setidaknya untuk sementara. Dengan kunci asing di tempat, ini bisa sangat sulit dan dalam beberapa RDBMS menonaktifkan batasan kunci asing akan menyebabkan pembangunan kembali tabel, proses yang memakan waktu yang dapat memerlukan downtime substansial.

Memahami bahwa saya termasuk peringatan bahwa Anda harus menggunakan kerangka kerja yang kuat yang mampu memahami integritas referensial eksternal ke database. Namun, Anda mungkin akan berakhir dengan beberapa masalah integritas referensial. Namun, ada banyak kasus di mana itu bukan masalah besar untuk memiliki baris yatim atau pelanggaran integritas referensial kecil. Saya berpendapat bahwa sebagian besar aplikasi web termasuk dalam kategori ini.

Yang sedang berkata, tidak ada yang memulai sebagai Facebook. Mulailah dengan mendefinisikan kunci asing di basis data Anda. Monitor. Jika Anda akhirnya mengalami masalah, pahamilah bahwa Anda mungkin perlu menghilangkan beberapa kendala tersebut untuk diukur.

Kesimpulannya: Kebanyakan database harus memiliki kunci asing. Lingkungan yang sangat konkuren mungkin lebih baik tanpa kunci asing. Jika Anda mencapai titik itu, Anda mungkin perlu mempertimbangkan untuk menjatuhkan batasan-batasan itu.

Aku akan pergi mengenakan setelan tahan api saya sekarang.

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

Dalam memikirkan konsekuensi penguncian kunci asing, saya lalai menyebutkan biaya semua pencarian baris tambahan yang secara implisit dihasilkan secara internal, menambah beban server.

Pada akhirnya, maksud saya adalah kunci asing tidak gratis. Dalam banyak kasus, biayanya sepadan, tetapi ada skenario di mana biaya itu melebihi manfaatnya.

EDIT 2012-03-23 ​​7:38 pagi

Mari kita konkret. Saya memilih MySQL / InnoDB dalam contoh ini, yang tidak begitu dihormati karena perilaku kunci asingnya, tetapi itulah yang paling saya kenal dan kemungkinan merupakan basis data web yang paling umum digunakan. Saya tidak yakin basis data lain akan lebih baik dengan contoh yang akan saya tunjukkan.

Pertimbangkan tabel anak dengan kunci asing yang merujuk orang tua. Sebagai contoh, lihat tabel film dan film_actor di database sampel sakila di MySQL:

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

Kendala yang relevan adalah film_actor (fk_film_actor_film) untuk contoh saya.

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

Perhatikan bahwa saya tidak dapat memperbarui bidang yang tidak terkait di baris induk saat memasukkan ke tabel anak. Ini terjadi karena InnoDB memegang kunci bersama pada baris di mana film.film_id = 508 karena kendala FK pada film_actor, sehingga UPDATE ke baris itu tidak bisa mendapatkan kunci eksklusif yang diperlukan. Jika Anda membalikkan operasi itu dan menjalankan UPDATE terlebih dahulu, Anda memiliki perilaku yang sama, tetapi INSERT diblokir.

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

Pertimbangkan userstabel dalam aplikasi web di mana sering ada puluhan tabel terkait. Pada dasarnya setiap operasi pada baris terkait mencegah pembaruan ke baris induk. Itu bisa menjadi masalah yang menantang ketika Anda memiliki beberapa hubungan kunci asing dan banyak konkurensi.

Kendala FK dapat membuat penyelesaian masalah untuk pemeliharaan meja juga sulit. Peter Zaitsev dari Percona memiliki posting blog tentang ini yang menjelaskan lebih baik daripada yang saya dapat: Membajak Innodb Foreign Keys .

Aaron Brown
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Paul White mengatakan GoFundMonica
6

Ini adalah praktik yang baik untuk menggunakan kunci asing dalam database. Itu membantu-

  • untuk menjaga integritas data dengan menghapus kemungkinan data yang tidak diinginkan
  • untuk meningkatkan kinerja. Dalam sistem yang bidang indeks otomatisnya, referensi kunci asing dapat memberikan peningkatan kinerja
  • untuk menulis lebih sedikit kode oleh programmer. suka, menggunakanON DELETE CASCADE
Abdul Ahad
sumber