เป็นคีย์ต่างประเทศเป็นคีย์หลักได้หรือไม่?


107

ฉันมีสองโต๊ะ:

  • ผู้ใช้ (ชื่อผู้ใช้รหัสผ่าน)
  • โปรไฟล์ (profileId, เพศ, วันเกิด, ... )

ขณะนี้ฉันกำลังใช้แนวทางนี้: แต่ละระเบียนโปรไฟล์มีฟิลด์ชื่อ "userId" เป็นคีย์ต่างประเทศซึ่งเชื่อมโยงไปยังตารางผู้ใช้ เมื่อผู้ใช้ลงทะเบียนบันทึกโปรไฟล์ของเขาจะถูกสร้างขึ้นโดยอัตโนมัติ

ฉันสับสนกับคำแนะนำของฉันเพื่อน: จะมีฟิลด์ "หมายเลขผู้ใช้" เป็นชาวต่างชาติและหลักที่สำคัญและลบฟิลด์ "profileId" แนวทางไหนดีกว่ากัน?


3
Entity Framework จะสร้างสิ่งนั้น (ด้วยรหัสก่อน) สำหรับความสัมพันธ์ zeroOrOne (และหนึ่ง) - ต่อหนึ่ง ดังนั้น ... เป็นไปได้ เป็นวิธีที่ดีที่สุดไหม ... นั่นเป็นอีกคำถาม แต่ก็ใช้ได้ ฉันไม่เคยทำแบบนั้นในขณะที่สร้างฐานข้อมูลของตัวเอง
Raphaël Althaus

คำตอบ:


137

คีย์ต่างประเทศมักเป็น "Allow Duplicates" ซึ่งจะทำให้ไม่เหมาะสมเป็นคีย์หลัก

ให้ค้นหาเขตข้อมูลที่ระบุแต่ละระเบียนในตารางโดยไม่ซ้ำกันหรือเพิ่มเขตข้อมูลใหม่ (ไม่ว่าจะเป็นจำนวนเต็มที่เพิ่มขึ้นอัตโนมัติหรือ GUID) เพื่อทำหน้าที่เป็นคีย์หลัก

ยกเว้นเพียงนี้ตารางมีแบบหนึ่งต่อหนึ่งความสัมพันธ์ที่ต่างประเทศที่สำคัญและหลักสำคัญของตารางที่เชื่อมโยงเป็นหนึ่งเดียวกัน


76
คีย์หลักแบบผสมที่ประกอบด้วยคีย์ต่างประเทศสองคีย์นั้นเหมาะอย่างยิ่งสำหรับการใช้ความสัมพันธ์แบบกลุ่มต่อกลุ่ม
พับขวา

2
@rezadru: ถึงฉันจะไม่เห็นด้วยกับ rightfold แต่คีย์ตัวแทนมักจะเป็นทางเลือกที่ดีกว่า
Robert Harvey

4
ไม่มีอะไรเกี่ยวกับคีย์ต่างประเทศที่กำหนดว่าเป็น 1 ต่อจำนวนมาก (หรือ "อนุญาตให้ซ้ำกัน" ตามที่เขียนไว้) ข้อ จำกัด ที่สำคัญและความเป็นเอกลักษณ์คือสองแนวคิดที่แยกจากกันในฐานข้อมูลและสามารถผสมกันได้อย่างง่ายดายเช่นเดียวกับการเพิ่มดัชนี (ซึ่งจะเป็นแนวคิดแยกที่สาม)
blindguy

ฉันเห็นด้วยกับ @RobertHarvey - คีย์ตัวแทนเป็นทางเลือกที่ดีกว่าในบางกรณีเช่นกัน ตัวอย่างเช่นคุณสามารถมีตารางกลางที่แมปความสัมพันธ์แบบกลุ่มต่อกลุ่มซึ่งใช้คีย์หลักเป็นส่วนหนึ่งของตารางอื่น หากไม่มีคีย์ตัวแทนคีย์แปลกปลอมทั้งหมดที่ทำเครื่องหมายเป็นคีย์หลักจะทำให้ตารางอื่น ๆ ของคุณบวม อย่างไรก็ตามหากคุณมีรหัสตัวแทนสิ่งที่ส่งผ่านไปก็คือกุญแจดอกเดียว ในความคิดของฉันมันง่ายและมีประสิทธิภาพมากกว่า
Pablo Alexis Domínguez Grau

42

คีย์หลักต้องไม่ซ้ำกันเสมอคีย์ต่างประเทศต้องอนุญาตค่าที่ไม่ซ้ำกันหากตารางเป็นความสัมพันธ์แบบหนึ่งต่อกลุ่ม เป็นการดีอย่างยิ่งที่จะใช้ Foreign Key เป็นคีย์หลักหากตารางเชื่อมต่อด้วยความสัมพันธ์แบบหนึ่งต่อกลุ่มไม่ใช่ความสัมพันธ์แบบหนึ่งต่อกลุ่ม หากคุณต้องการให้บันทึกผู้ใช้เดียวกันมีความเป็นไปได้ที่จะมีบันทึกโปรไฟล์ที่เกี่ยวข้องมากกว่า 1 รายการให้ใช้คีย์หลักแยกต่างหากมิฉะนั้นจะยึดติดกับสิ่งที่คุณมี


11

ใช่มันถูกกฎหมายที่จะให้คีย์หลักเป็นคีย์ต่างประเทศ นี่เป็นโครงสร้างที่หายาก แต่ใช้สำหรับ:

  • ความสัมพันธ์ 1: 1 ไม่สามารถรวมสองตารางในตารางเดียวได้เนื่องจากการอนุญาตและสิทธิ์ที่แตกต่างกันจะใช้เฉพาะในระดับตารางเท่านั้น (ณ ปี 2560 ฐานข้อมูลดังกล่าวจะเป็นเลขคี่)

  • ความสัมพันธ์ 1: 0..1 โปรไฟล์อาจมีหรือไม่มีขึ้นอยู่กับประเภทของผู้ใช้

  • ประสิทธิภาพเป็นปัญหาและการออกแบบทำหน้าที่เป็นพาร์ติชัน: ไม่ค่อยมีการเข้าถึงตารางโปรไฟล์โฮสต์บนดิสก์แยกต่างหากหรือมีนโยบายการแตกต่างกันเมื่อเทียบกับตารางผู้ใช้ จะไม่สมเหตุสมผลหากที่เก็บข้อมูลขีดเส้นใต้เป็นแนวคอลัมน์


จะมีประสิทธิภาพเชิงลบหากมีการรวมตารางบ่อยๆซึ่งนำไปสู่คำแนะนำปกติที่ว่า 1 ตารางดีกว่า ในบางกรณีข้อมูลจะถูกเข้าถึงโดยแยกจากกันเสมอไม่รวมเข้าด้วยกันและอาจมีประโยชน์ต่อองค์กรในการมีสองตารางที่มีความสัมพันธ์แบบ 1: 1
blindguy

4

โดยทั่วไปถือว่าเป็นการปฏิบัติที่ไม่ดีในการมีความสัมพันธ์แบบหนึ่งต่อหนึ่ง เนื่องจากคุณสามารถมีข้อมูลที่แสดงในตารางเดียวและได้ผลลัพธ์เดียวกัน

อย่างไรก็ตามมีบางกรณีที่คุณอาจไม่สามารถทำการเปลี่ยนแปลงเหล่านี้กับตารางที่คุณอ้างถึงได้ ในกรณีนี้ไม่มีปัญหาในการใช้ Foreign key เป็นคีย์หลัก อาจช่วยให้มีคีย์ผสมซึ่งประกอบด้วยคีย์หลักที่ไม่ซ้ำกันโดยอัตโนมัติและคีย์ภายนอก

ฉันกำลังทำงานกับระบบที่ผู้ใช้สามารถเข้าสู่ระบบและสร้างรหัสการลงทะเบียนเพื่อใช้กับแอพได้ ด้วยเหตุผลที่ฉันจะไม่เข้าไปฉันไม่สามารถเพิ่มคอลัมน์ที่จำเป็นในตารางผู้ใช้ได้ ดังนั้นฉันจะลงหนึ่งต่อหนึ่งเส้นทางด้วยตารางรหัส


2
ฉันเห็นด้วยกับคุณเป็นส่วนใหญ่ว่าการมีข้อมูลทั้งหมดในตารางเดียวกันกับคอลัมน์เพิ่มเติมมีข้อดีหลายประการ แม้ว่าจะเขียนว่า .. "คุณสามารถมีข้อมูลที่แสดงในตารางเดียวและได้ผลลัพธ์เดียวกัน" .. : การมีตารางแยกกันจะมีประโยชน์ตัวอย่างเช่นที่นี่หากรายการตารางโปรไฟล์เป็นทางเลือก ตัวอย่างเช่นลูกค้าทุกธนาคารอาจไม่มีการลงทะเบียนธนาคารทางอินเทอร์เน็ต ในกรณีนี้สามารถใช้ตารางการลงทะเบียน IB เพื่อ จำกัด ตารางอื่น ๆ ไม่ให้มีบันทึกเด็กเพิ่มเติม อีกครั้งที่นี่สามารถทำได้ด้วย PK ใหม่สำหรับโต๊ะลงทะเบียน IB ด้วย
Teddy

1
@ เท็ดดี้เช่นเดียวกันฉันเห็นด้วยกับสิ่งที่คุณพูดมากที่สุด อย่างไรก็ตามในคำถามเดิมพวกเขาระบุว่า "... บันทึกโปรไฟล์ของเขาถูกสร้างขึ้นโดยอัตโนมัติ ... " ซึ่งหมายความว่าตารางโปรไฟล์ไม่สามารถเลือกได้ ในสถานการณ์ที่ตารางโปรไฟล์เป็นทางเลือกใช่การมีตารางแยกต่างหากนั้นทำได้ แต่อีกครั้งพวกเขาสามารถใช้คอลัมน์ที่ว่างเปล่าในตารางเดียวกันได้
Tshsmith

1
การใช้ตารางที่สองแยกต่างหากเราสามารถป้องกันไม่ให้เข้ามาในตารางที่สามซึ่งอนุญาตให้เฉพาะผู้ที่มีรายการในตารางที่สองเท่านั้น
Teddy

แน่นอน แต่ถ้าเรารวมตาราง 1 ถึง 1 เราสามารถป้องกันไม่ให้คนที่มีค่า null เข้าถึงตารางที่สาม (ในทางเทคนิคที่สองตอนนี้) แต่คำถามที่ OP ถามมีบรรทัด "... เมื่อสมัคร .. ... บันทึกโปรไฟล์ของเขาจะถูกสร้างขึ้นโดยอัตโนมัติ ... " ทำให้ซ้ำซ้อน
Tshsmith

เหตุผลหลักของฉันในการพิจารณาเรื่องนี้คือในคลังข้อมูลการแยกตารางข้อเท็จจริงและตารางมิติข้อมูลเป็นแนวทางปฏิบัติที่ดี ตารางข้อเท็จจริงและมิติข้อมูลที่แยกจากกันเป็นตัวชี้นำที่มีประโยชน์เมื่อทำงานกับซอฟต์แวร์เช่น PowerPivot, PowerBI และ Tableau
Marco Rosas

4

ใช่ Foreign Key อาจเป็นคีย์หลักในกรณีที่มีความสัมพันธ์แบบหนึ่งต่อหนึ่งระหว่างตารางเหล่านั้น


2
สิ่งนี้มีประโยชน์สำหรับการออกแบบ supertype-subtype คีย์หลักของตารางประเภทย่อยควรอ้างอิงคีย์ต่างประเทศกับตารางซุปเปอร์ไทป์
axelioo

2

ฉันจะไม่ทำอย่างนั้น ฉันจะเก็บprofileIDเป็นคีย์หลักของตารางProfile

คีย์ต่างประเทศเป็นเพียงข้อ จำกัด ในการอ้างอิงระหว่างสองตาราง

อาจโต้แย้งได้ว่าคีย์หลักมีความจำเป็นเนื่องจากเป็นเป้าหมายของคีย์ต่างประเทศใด ๆ ที่อ้างถึงจากตารางอื่น คีย์ต่างประเทศคือชุดของคอลัมน์อย่างน้อยหนึ่งคอลัมน์ในตารางใด ๆ (ไม่จำเป็นต้องเป็นคีย์ตัวเลือก แต่เป็นคีย์หลักของตารางนั้น) ซึ่งอาจเก็บค่าที่พบในคอลัมน์คีย์หลักของบางคอลัมน์ โต๊ะอื่น ๆ ดังนั้นเราต้องมีคีย์หลักเพื่อให้ตรงกับคีย์ต่างประเทศ หรือต้องเรา? จุดประสงค์เดียวของคีย์หลักในคู่คีย์หลัก / คีย์ต่างประเทศคือการให้การรวมที่ไม่คลุมเครือ - เพื่อรักษาความสมบูรณ์ของการอ้างอิงตามตาราง "ต่างประเทศ" ซึ่งเก็บคีย์หลักที่อ้างอิง สิ่งนี้ทำให้มั่นใจได้ว่าค่าที่ Foreign Key อ้างถึงจะถูกต้องเสมอ (หรือเป็นโมฆะหากอนุญาต)

http://www.aisintl.com/case/primary_and_foreign_key.html


1
อาจจะ - ถ้าคุณมีข้อ จำกัด FK ระหว่าง User.UserID และ Profile.UserID ขอแนะนำอย่างยิ่งให้มีดัชนีใน Profile.UserID ทำไมไม่สร้างดัชนีคลัสเตอร์หลักบนโปรไฟล์ตารางบันทึกดัชนีที่สองและงานที่ไม่จำเป็นจำนวนมากสำหรับเครื่องมือฐานข้อมูล
Reversed Engineer

1

ขึ้นอยู่กับธุรกิจและระบบ

หาก userId ของคุณไม่ซ้ำกันและจะไม่ซ้ำกันตลอดเวลาคุณสามารถใช้ userId เป็นคีย์หลักได้ แต่ถ้าคุณต้องการขยายระบบของคุณก็จะทำให้เรื่องยากขึ้น ฉันแนะนำให้คุณเพิ่มคีย์ต่างประเทศในผู้ใช้ตารางเพื่อสร้างความสัมพันธ์กับโปรไฟล์ตารางแทนที่จะเพิ่มคีย์ต่างประเทศในโปรไฟล์ตาราง


0

คำตอบสั้น ๆ : DEPENDS .... ในกรณีนี้อาจจะไม่เป็นไร อย่างไรก็ตามผู้เชี่ยวชาญจะแนะนำให้ต่อต้านทุกครั้ง รวมถึงกรณีของคุณ

ทำไม?

คีย์แทบจะไม่ซ้ำกันในตารางเมื่อเป็นสิ่งแปลกปลอม (มาจากตารางอื่น) ไปยังตารางที่มีปัญหา ตัวอย่างเช่นรหัสรายการอาจไม่ซ้ำกันในตาราง ITEMS แต่ไม่อยู่ในตารางคำสั่งซื้อเนื่องจากรายการประเภทเดียวกันมักจะอยู่ในลำดับอื่น ในทำนองเดียวกันรหัสคำสั่งซื้ออาจไม่ซ้ำกัน (อาจ) ในตารางคำสั่งซื้อ แต่ไม่มีในตารางอื่น ๆ เช่น ORDER_DETAILS ที่สามารถมีคำสั่งซื้อที่มีรายการโฆษณาหลายรายการได้และหากต้องการค้นหารายการใดรายการหนึ่งในคำสั่งซื้อหนึ่ง ๆ คุณต้องมีการเชื่อมสองรายการเข้าด้วยกัน FK (order_id และ item_id) เป็น PK สำหรับตารางนี้

ฉันไม่ใช่ผู้เชี่ยวชาญด้าน DB แต่ถ้าคุณสามารถปรับเหตุผลให้มีค่าที่สร้างขึ้นโดยอัตโนมัติเป็น PK ของคุณฉันจะทำเช่นนั้น หากไม่สามารถใช้งานได้จริง FK สองตัว (หรืออาจมากกว่านั้น) ต่อกันอาจใช้เป็น PK ของคุณได้ แต่ฉันไม่สามารถนึกถึงกรณีใด ๆ ที่สามารถใช้ค่า FK เดียวเป็นค่า PK ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.