การปฏิบัติที่ดีที่สุดสำหรับคีย์หลักในตารางคืออะไร


256

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

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

หมายเลข 3 จะใช้สำหรับการค้นหาที่ค่อนข้างเล็กส่วนใหญ่อ่านตารางที่อาจมีรหัสสตริงความยาวคงที่ที่ไม่ซ้ำกันหรือค่าตัวเลขเช่นปีหรือตัวเลขอื่น ๆ

ส่วนใหญ่ตารางอื่น ๆ ทั้งหมดจะมีเลขจำนวนเต็มเพิ่มอัตโนมัติหรือคีย์หลักของตัวระบุที่ไม่ซ้ำกัน

คำถาม :-)

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

  • datetime / ตัวอักษร
  • datetime / จำนวนเต็ม
  • datetime / varchar
  • ถ่าน / nvarchar / nvarchar

มีกรณีที่ถูกต้องสำหรับเรื่องนี้? ฉันจะกำหนดคอลัมน์ข้อมูลประจำตัวหรือรหัสเฉพาะสำหรับกรณีเหล่านี้อยู่เสมอ

นอกจากนี้ยังมีหลายตารางที่ไม่มีคีย์หลักเลย อะไรคือเหตุผลที่ถูกต้องถ้ามีสำหรับสิ่งนี้?

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

คำถามที่สามที่จะช่วยฉันถอดรหัสคำตอบ: ในกรณีที่มีหลายคอลัมน์ที่ใช้ในการประกอบคีย์หลักแบบผสมจะมีความได้เปรียบเฉพาะกับวิธีนี้เทียบกับคีย์ตัวแทน / เทียมหรือไม่ ฉันคิดว่าส่วนใหญ่เกี่ยวกับประสิทธิภาพการบำรุงรักษาการบริหาร ฯลฯ ?


ฉันพบทักษะฐานข้อมูล: แนวทางที่มีเหตุผลในการเลือกคีย์หลักเพื่อการอ่านที่ดีและฉันทำตามส่วนใหญ่ตามที่ระบุไว้
2864740

คำตอบ:


254

ฉันทำตามกฎสองสามข้อ:

  1. คีย์หลักควรมีขนาดเล็กเท่าที่จำเป็น ต้องการประเภทที่เป็นตัวเลขเพราะประเภทที่เป็นตัวเลขจะถูกจัดเก็บในรูปแบบที่กะทัดรัดกว่ารูปแบบอักขระ นี่เป็นเพราะคีย์หลักส่วนใหญ่จะเป็นคีย์ต่างประเทศในตารางอื่นเช่นเดียวกับที่ใช้ในหลายดัชนี ยิ่งคีย์ของคุณเล็กลงดัชนียิ่งเล็กลงหน้าเพจที่น้อยลงในแคชที่คุณจะใช้
  2. คีย์หลักไม่ควรเปลี่ยนแปลง การอัปเดตคีย์หลักควรอยู่นอกคำถามเสมอ นี่เป็นเพราะส่วนใหญ่มีแนวโน้มที่จะใช้ในหลายดัชนีและใช้เป็นคีย์ต่างประเทศ การอัปเดตคีย์หลักเดียวอาจทำให้เกิดการกระเพื่อมของการเปลี่ยนแปลงได้
  3. อย่าใช้ "คีย์หลักของปัญหาของคุณ" เป็นคีย์หลักของโมเดลเชิงตรรกะ ตัวอย่างเช่นหมายเลขหนังสือเดินทางหมายเลขประกันสังคมหรือหมายเลขสัญญาของพนักงานเนื่องจาก "คีย์หลัก" เหล่านี้สามารถเปลี่ยนแปลงได้ในสถานการณ์จริง

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


3
ฉันชอบมัน! คุณมีเอกสารใด ๆ สำหรับพื้นฐานของ "กฎ" ของคุณหรือไม่? ขอบคุณ!
Lloyd Cotten

4
ไม่เพียงประสบการณ์ เมื่อจัดการกับฐานข้อมูล "เล็ก" สิ่งนี้ไม่สำคัญมาก แต่เมื่อคุณจัดการกับฐานข้อมูลขนาดใหญ่สิ่งเล็กน้อยทั้งหมดมีความสำคัญ ลองจินตนาการดูว่าคุณมี 1 พันล้านแถวที่มี pk มากหรือน้อยเมื่อเทียบกับการใช้ข้อความหรือ guid's มีความแตกต่างอย่างมาก!
Logicalmind

44
เพียงจำไว้ว่าให้ใส่ดัชนีที่ไม่ซ้ำกันในคีย์ธรรมชาติ (ถ้ามีอยู่จริงซึ่งมักจะไม่ใช่กรณี) เมื่อคุณใช้คีย์ประดิษฐ์
HLGEM

3
@Lloyd Cotten: นี่คือสิ่งที่ผู้ให้บริการเครื่องมือข้อมูลขนาดใหญ่กล่าวว่าในการสนับสนุนของการปกครองจำนวน 1: skyfoundry.com/forum/topic/24 มันทำให้ฉันมั่นใจที่จะกลับไปที่Ints
hobs

4
แม้ว่าคุณจะ "รู้" ว่า "คีย์ธรรมชาตินั้นเล็กและจะไม่มีวันเปลี่ยนแปลง" ให้คิดสองครั้ง "เราไม่เคยใช้รหัสเหล่านี้ซ้ำ" เป็นคำพูดสุดท้ายที่มีชื่อเสียง .... เกี่ยวกับสิ่งเดียวที่ตกอยู่ในหมวดหมู่ของสิ่งเล็ก ๆ ที่ไม่เคยเปลี่ยนแปลงคือมาตรฐาน ISO และมาตรฐานอื่น ๆ (รหัสประเทศรหัสสนามบิน iata) สิ่งที่ชอบ "การแสดงตัวอักษร 2 ตัวสำหรับแบรนด์ภายในนี้คืออะไร" ... คิดอย่างรอบคอบก่อนที่จะสมมติว่า "มัน" จะไม่เปลี่ยนแปลงคุณกำลังตัดสินใจทางการเงินเพียงครั้งเดียวจากการสร้างฐานข้อมูลใหม่
Andrew Hill

90

คีย์โองการทางธรรมชาติเป็นการถกเถียงทางศาสนาในชุมชนฐานข้อมูล - ดูบทความนี้และอื่น ๆ ที่ลิงก์ไปถึง ฉันไม่ชอบที่จะมีกุญแจปลอม ๆ หรือไม่เคยมีมัน ฉันจะตัดสินใจเป็นรายกรณีเช่น:

  • สหรัฐอเมริกา: ฉันจะใช้ state_code ('TX' สำหรับเท็กซัสและอื่น ๆ ) แทนที่จะเป็น state_id = 1 สำหรับเท็กซัส
  • พนักงาน: ฉันมักจะสร้างการหลอกลวง Employee_id เพราะมันยากที่จะหาสิ่งอื่นที่ใช้งานได้ SSN หรือเทียบเท่าอาจใช้งานได้ แต่อาจมีปัญหาเช่นผู้เข้าร่วมใหม่ที่ยังไม่ได้ให้ SSN ของตน
  • ประวัติเงินเดือนของพนักงาน: (employee_id, start_date) ฉันจะไม่สร้าง Employee_salary_history_id ที่ประดิษฐ์ ประเด็นอะไรที่จะให้บริการ (นอกเหนือจาก"ความมั่นคงที่โง่เขลา" )

เมื่อใดก็ตามที่ใช้คีย์ประดิษฐ์คุณควรประกาศข้อ จำกัด ที่เป็นเอกลักษณ์ของคีย์ธรรมชาติเสมอ ตัวอย่างเช่นใช้ state_id หากคุณต้องการ แต่คุณควรประกาศข้อ จำกัด ที่ไม่ซ้ำกันใน state_code มิฉะนั้นคุณจะต้องจบลงด้วย:

state_id    state_code   state_name
137         TX           Texas
...         ...          ...
249         TX           Texas

9
ในบางกรณีด้วย SQL Server 2005/2008 คีย์ธรรมชาติ (ข้อความ) อาจเร็วกว่าคีย์ int ฉันมีแอพที่มีรหัสที่เข้าใจง่ายสำหรับตัวอักษร 7-8 ตัวที่เราใช้เป็นคีย์หลักและนั่นก็เร็วกว่า (และมักจะสะดวกกว่า) มากกว่าตัวแทนเสมือน เราต้องการรหัสต่อไปเพื่อที่เราจะได้รหัสที่มนุษย์สามารถอ่าน / จดจำได้ซึ่งเราสามารถถ่ายโอนได้อย่างปลอดภัยโดยไม่มีข้อขัดแย้งกับอินสแตนซ์ของแอปพลิเคชันอื่น (หลายไซต์ที่รวมเข้าไปในเว็บไซต์ที่ใหญ่กว่า)
lambacck

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

@ onedaywhen- ฉันไม่ต้องการ เชื่อใจเจ้าหน้าที่บุคคล ผู้คนออกไปคนใหม่มาและมีความคิดที่แตกต่าง ให้พวกเขาเข้าถึงตัวระบุที่พวกเขาคิดว่าเป็นเอกลักษณ์ / พวกเขาต้องการใช้ แต่ภายในฐานข้อมูลนั้น DBA ควรตัดสินใจด้วยตัวเอง
Dave Pile

1
โปรดทราบว่า SSN นั้นไม่ได้มีความเป็นเอกลักษณ์ในทุกประเทศ อย่างน้อยในออสเตรียหลายคนอาจใช้หมายเลขเดียวกัน
maja

นอกจากนี้ในบางประเทศ (ฉันคิดว่าแม้แต่ในสหรัฐอเมริกา) พวกเขาแนะนำให้ไม่เปิดเผย SSN
Stijn de Witt

25

เป็นเพียงความคิดเห็นเพิ่มเติมเกี่ยวกับสิ่งที่มักถูกมองข้าม บางครั้งการไม่ใช้คีย์ตัวแทนอาจมีประโยชน์ในตารางลูก สมมติว่าเรามีการออกแบบที่ช่วยให้คุณเรียกใช้หลาย บริษัท ภายในฐานข้อมูลเดียว (อาจเป็นโซลูชันที่โฮสต์หรืออะไรก็ตาม)

สมมติว่าเรามีตารางและคอลัมน์เหล่านี้:

Company:
  CompanyId   (primary key)

CostCenter:
  CompanyId   (primary key, foreign key to Company)
  CostCentre  (primary key)

CostElement
  CompanyId   (primary key, foreign key to Company)
  CostElement (primary key)

Invoice:
  InvoiceId    (primary key)
  CompanyId    (primary key, in foreign key to CostCentre, in foreign key to CostElement)
  CostCentre   (in foreign key to CostCentre)
  CostElement  (in foreign key to CostElement)

ในกรณีที่บิตสุดท้ายไม่สมเหตุสมผลInvoice.CompanyIdเป็นส่วนหนึ่งของคีย์ต่างประเทศสองตัวอันหนึ่งถึงตารางCostCentreและอีกอันหนึ่งไปยังตารางCostElement คีย์หลักคือ ( InvoiceId , CompanyId )

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

โอกาสน้อยลงที่จะทำให้ดีขึ้น


6
นี่เป็นข้อเสียที่ไม่ได้อ้างถึงเมื่อใช้คีย์ตัวแทน หากตารางมีคีย์ตัวแทนฉันยังคงสามารถใช้มันกับข้อ จำกัด ประเภทนี้ได้ น่าเสียดายที่ข้อ จำกัด นั้นต้องการดัชนีและมันแปลกที่จะสร้างดัชนีเฉพาะบน (surrogate_key, other_column) เมื่อ (surrogate_key) มีเอกลักษณ์เฉพาะด้วยตัวเอง นอกจากนี้ (other_column) มักซ้ำซ้อนกันอย่างสิ้นเชิงในตารางแผนที่เนื่องจาก (surrogate_key) มีความโดดเด่นในต่างประเทศ ตัวแทนสามารถสร้างสิ่งที่สกปรกได้จริง ๆ
ซามูเอลแดเนียล

24

ฉันหลีกเลี่ยงการใช้คีย์ธรรมชาติด้วยเหตุผลง่ายๆข้อเดียว - ความผิดพลาดของมนุษย์ แม้ว่าตัวระบุที่เป็นเอกลักษณ์ตามธรรมชาติมักจะมีให้ใช้งาน (SSN, VIN, หมายเลขบัญชี ฯลฯ ) แต่พวกเขาต้องการให้คนป้อนอย่างถูกต้อง หากคุณใช้ SSN เป็นคีย์หลักมีคนส่งตัวเลขสองสามตัวระหว่างการป้อนข้อมูลและไม่พบข้อผิดพลาดในทันทีคุณจะต้องเผชิญกับการเปลี่ยนคีย์หลัก

คีย์หลักของฉันได้รับการจัดการโดยโปรแกรมฐานข้อมูลในพื้นหลังและผู้ใช้ไม่เคยรู้เลย


1
ฉันทำงานกับฐานข้อมูลบางอย่างที่ใช้ SSNs หรือ ID ภาษีเป็นคีย์หลัก ไม่มีประสิทธิภาพเมื่อมันมาถึงการจัดเก็บและการอ้างอิงคีย์ต่างประเทศ ไม่ต้องพูดถึงว่า SSN ของบุคคลนั้นสามารถเปลี่ยนแปลงได้ ดังนั้นฉันเห็นด้วยกับคุณอย่างสมบูรณ์
Alex Jorgenson

13

ไม่มีปัญหาในการสร้างคีย์หลักของคุณจากฟิลด์ต่าง ๆ นั่นคือคีย์ธรรมชาติกุญแจสำคัญในธรรมชาติ

คุณสามารถใช้คอลัมน์ข้อมูลประจำตัว (ที่เกี่ยวข้องกับดัชนีที่ไม่ซ้ำกันในเขตข้อมูลผู้สมัคร) เพื่อสร้างคีย์ตัวแทนกุญแจแทน

นั่นเป็นการสนทนาเก่า ๆ ฉันชอบปุ่มตัวแทนในสถานการณ์ส่วนใหญ่

แต่ไม่มีข้อแก้ตัวสำหรับการขาดคีย์

RE: แก้ไข

ใช่มีข้อโต้แย้งมากมายเกี่ยวกับเรื่องนั้น: D

ฉันไม่เห็นความได้เปรียบใด ๆ ที่ชัดเจนเกี่ยวกับคีย์ธรรมชาตินอกเหนือจากความจริงที่ว่าพวกเขาเป็นตัวเลือกที่เป็นธรรมชาติ คุณจะคิดในชื่อ, SocialNumber - หรืออะไรทำนองนั้นแทนidPerson idPerson

คีย์ตัวแทนเป็นคำตอบสำหรับปัญหาบางอย่างที่คีย์ธรรมชาติมี (การเผยแพร่การเปลี่ยนแปลงเช่น)

เมื่อคุณคุ้นเคยกับตัวแทนดูเหมือนว่าจะสะอาดและจัดการได้มากกว่า

แต่ในที่สุดคุณจะพบว่ามันเป็นเพียงแค่เรื่องของรสนิยม - หรือความคิด - ผู้คน "คิดว่าดีกว่า" ด้วยกุญแจธรรมชาติและคนอื่น ๆ ก็ไม่ชอบ


13
ผู้คน "คิดดีขึ้น" ด้วยกุญแจธรรมชาติ เครื่องจักรและฐานข้อมูลไม่
FDCastel

11

ตารางควรมีคีย์หลักตลอดเวลา เมื่อไม่เป็นเช่นนั้นก็ควรจะเป็นช่อง AutoIncrement

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

บางความคิดเห็นเกี่ยวกับตารางลิงค์นี้ถูกต้องมันเป็นข้อยกเว้น แต่เขตข้อมูลควรเป็น FK เพื่อรักษาความสมบูรณ์และเป็นบางกรณีเขตข้อมูลเหล่านั้นอาจเป็นคีย์หลักเช่นกันหากทำซ้ำในลิงก์ไม่ได้รับอนุญาต ... แต่เพื่อเก็บไว้ใน รูปแบบที่เรียบง่ายเนื่องจากมีข้อยกเว้นบางอย่างในการเขียนโปรแกรมคีย์หลักควรมีอยู่เพื่อรักษาความสมบูรณ์ของข้อมูลของคุณ


ฉันเห็นด้วย. และในกรณีที่ต้องใส่ข้อมูลจำนวนมากให้ลบข้อ จำกัด คีย์หลัก (หรือใช้ INSERT IDENTITY ON ใน TSQL) และนำกลับมาใช้ใหม่ :)
Andrew Rollings

1
มีข้อยกเว้นคือ: ตารางลิงก์อย่างชัดเจน
annakata

อีกเหตุผลหนึ่ง: หากไม่มีคีย์ PK / คีย์ที่ไม่ซ้ำเบราว์เซอร์ตาราง (ฉันหมายถึงบางอย่างเช่น Access / SQL Server Management Studio) จะปฏิเสธที่จะอัปเดต / ลบแถวเดียวที่มีแถวซ้ำ คุณจะต้องเขียน SQL สำหรับสิ่งนั้น
Dennis C

เป็นเรื่องปกติที่จะไม่ใช้ PK จากตารางข้อมูลคลังข้อมูล ใน Oracle คุณสามารถอ้างอิง ROWID pseudocolumn เป็นตัวระบุที่ไม่ซ้ำกันในระยะสั้น (เช่นอย่าเก็บไว้ที่ใดที่หนึ่งและคาดว่าจะไม่เปลี่ยนแปลง)
David Aldridge

9

นอกจากคำตอบที่ดีเหล่านั้นแล้วฉันแค่อยากจะแบ่งปันบทความดีๆที่ฉันอ่านอ่านการถกเถียงหลักสำคัญอย่างยิ่ง

เพียงเพื่อพูดไม่กี่คะแนน:

นักพัฒนาจะต้องใช้กฎสองสามข้อเมื่อเลือกคีย์หลักสำหรับแต่ละตาราง:

  • คีย์หลักต้องระบุแต่ละระเบียนโดยไม่ซ้ำกัน
  • ค่าคีย์หลักของเร็กคอร์ดต้องไม่เป็นค่าว่าง
  • คีย์ - ค่าหลักต้องมีอยู่เมื่อสร้างเรคคอร์ด
  • คีย์หลักจะต้องคงที่ - คุณไม่สามารถเปลี่ยนฟิลด์คีย์หลักได้
  • คีย์หลักต้องมีขนาดกะทัดรัดและมีแอตทริบิวต์ที่เป็นไปได้น้อยที่สุด
  • ไม่สามารถเปลี่ยนค่าคีย์หลัก

คีย์ธรรมชาติ (มีแนวโน้ม) ผิดกฎ กุญแจตัวแทนปฏิบัติตามกฎ (คุณควรอ่านบทความนี้ให้ดีและคุ้มค่ากับเวลาของคุณ!)


7

อะไรคือความพิเศษเกี่ยวกับคีย์หลัก?

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

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

  • ASIDE: ผลข้างเคียงที่น่าเสียดายของฐานข้อมูลส่วนใหญ่ที่ได้รับการออกแบบและพัฒนาโดยโปรแกรมเมอร์แอปพลิเคชั่น (ซึ่งบางครั้งฉันก็คือ) สิ่งที่ดีที่สุดสำหรับแอพพลิเคชั่นหรือเฟรมเวิร์กแอพพลิเคชันมักจะเป็นตัวเลือกหลักสำหรับตาราง สิ่งนี้นำไปสู่คีย์จำนวนเต็มและ GUID (เนื่องจากง่ายต่อการใช้สำหรับกรอบงานแอปพลิเคชัน) และการออกแบบตารางเสาหิน (เนื่องจากสิ่งเหล่านี้จะลดจำนวนของวัตถุเฟรมเวิร์กแอปพลิเคชันที่จำเป็นในการแสดงข้อมูลในหน่วยความจำ) การตัดสินใจออกแบบฐานข้อมูลของแอพพลิเคชั่นเหล่านี้นำไปสู่ปัญหาความมั่นคงของข้อมูลที่สำคัญเมื่อใช้ในระดับ กรอบแอปพลิเคชันที่ออกแบบในลักษณะนี้จะนำไปสู่ตารางในเวลาออกแบบตามธรรมชาติ “ ระเบียนบางส่วน” ถูกสร้างขึ้นในตารางและข้อมูลที่กรอกในช่วงเวลาหนึ่ง หลีกเลี่ยงการโต้ตอบหลายตารางหรือเมื่อใช้ทำให้ข้อมูลไม่สอดคล้องกันเมื่อแอปพลิเคชันทำงานไม่ถูกต้อง การออกแบบเหล่านี้นำไปสู่ข้อมูลที่ไม่มีความหมาย (หรือยากต่อการเข้าใจ) ข้อมูลแผ่กระจายไปทั่วตาราง (คุณต้องดูที่ตารางอื่นเพื่อให้เข้าใจถึงตารางปัจจุบัน) และข้อมูลที่ซ้ำซ้อน

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

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

ต้องบอกว่านี้ฉันรู้สึกขอบคุณสำหรับฐานข้อมูลที่ออกแบบมาไม่ดีมากมายที่มีอยู่ในธุรกิจปัจจุบัน (behemoth-surrogate-keyed-data-damage-1NF behemoths ที่ไม่มีความหมาย) เพราะนั่นหมายความว่ามีจำนวนงานไม่รู้จบสำหรับคนที่เข้าใจการออกแบบฐานข้อมูลที่เหมาะสม . แต่ในด้านเศร้าบางครั้งมันทำให้ฉันรู้สึกเหมือน Sisyphus แต่ฉันคิดว่าเขามีหนึ่ง heck ของ 401k (ก่อนการแข่งขัน) อยู่ห่างจากบล็อกและเว็บไซต์สำหรับคำถามการออกแบบฐานข้อมูลที่สำคัญ หากคุณกำลังออกแบบฐานข้อมูลให้ค้นหา CJ Date นอกจากนี้คุณยังสามารถอ้างอิง Celko สำหรับ SQL Server แต่ถ้าคุณถือจมูกของคุณก่อน ทางด้าน Oracle อ้างอิง Tom Kyte


1
"ด้วยตรรกะนี้คุณไม่ควรลบระเบียนออกจากตารางด้วยหนึ่งคีย์จากนั้นเพิ่มอีกระเบียนหนึ่งด้วยคีย์ที่สอง" - มีกรณีสำหรับสิ่งนี้และนั่นคือสิ่งที่มีประสิทธิภาพสิ่งที่ประโยค "ON DELETE RESTRICT" ในคีย์ต่างประเทศจะทำ ในบางกรณี (พูดที่ต้องการหลักฐานการตรวจสอบ) ฟิลด์บูลีน "ถูกลบ" จะดีกว่าการอนุญาตให้ลบเรกคอร์ด
Waz

6

คีย์ธรรมชาติ (ถ้ามี) มักจะดีที่สุด ดังนั้นหากวันที่และเวลา / ถ่านระบุแถวอย่างไม่ซ้ำกันและทั้งสองส่วนมีความหมายต่อแถวนั่นยอดเยี่ยมมาก

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


9
มักจะดีที่สุด ฉันไม่มีพื้นฐานทางวิทยาศาสตร์ใด ๆ แต่ฉันคิดว่าคนส่วนใหญ่มักจะชอบกุญแจตัวแทนเหนือธรรมชาติ ในหลายกรณีไม่มีคีย์ธรรมชาติ
JC

3
ควรมีคีย์ธรรมชาติสำหรับทุกแถวในฐานข้อมูลของคุณเสมอ คีย์ "ธรรมชาติ" นั้นอาจเป็นสิ่งที่สร้างขึ้นในโลกธุรกิจหรือระบบเทคนิคของคุณ แต่ควรมีอยู่เสมอ
Tom H

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

8
2. หากคุณรับกุญแจจากโลกธรรมชาติโลกธรรมชาติจะเปลี่ยนเพื่อทำลายกุญแจของคุณ หากคุณใช้หมายเลขโทรศัพท์คุณจะได้รับผู้ใช้สองคนจากครัวเรือนเดียวกัน หากคุณใช้นามสกุลพวกเขาจะแต่งงาน หากคุณใช้ SSN กฎหมายความเป็นส่วนตัวจะเปลี่ยนแปลงและกำหนดให้คุณลบออก
James Orr

2
@Barry: RE: # 2 หากโลกธรรมชาติเปลี่ยนไปและนั่นทำให้คีย์ธรรมชาติของคุณเปลี่ยนนั่นหมายความว่าคุณทำงานได้ไม่ดีในการเลือกคีย์ธรรมชาติ โดยนิยามคีย์ธรรมชาติไม่เปลี่ยนแปลงตลอดเวลา
Tom H

6

นี่คือกฎง่ายๆที่ฉันได้ตัดสินหลังจากประสบการณ์การพัฒนามากกว่า 25 ปี

  • ตารางทั้งหมดควรมีคีย์หลักคอลัมน์เดียวที่เพิ่มขึ้นอัตโนมัติ
  • รวมไว้ในมุมมองใด ๆ ที่มีความหมายว่าสามารถอัปเดตได้
  • คีย์หลักไม่ควรมีความหมายใด ๆ ในบริบทของแอปพลิเคชันของคุณ ซึ่งหมายความว่าไม่ควรเป็น SKU หรือหมายเลขบัญชีหรือรหัสพนักงานหรือข้อมูลอื่นใดที่มีความหมายต่อแอปพลิเคชันของคุณ มันเป็นเพียงคีย์เฉพาะที่เกี่ยวข้องกับเอนทิตี

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

การมีคีย์หลักที่มีค่าเดียวจะทำให้ UPSERT มีประสิทธิภาพตรงไปตรงมามาก

ใช้ดัชนีเพิ่มเติมเพื่อรองรับคีย์หลายคอลัมน์ที่มีความหมายในแอปพลิเคชันของคุณ


5

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

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

ฉันไม่ชอบคีย์ธรรมชาติเนื่องจากประสบการณ์ของฉันกับการเปลี่ยนแปลงกฎเกณฑ์ทางธุรกิจ แต่ถ้าคุณแน่ใจว่ามันจะไม่เปลี่ยนแปลงก็อาจป้องกันไม่ให้เข้าร่วมที่สำคัญบางอย่าง


8
และฉันได้เห็นข้อมูลที่ SSN ไม่ซ้ำกันแม้ว่ามันควรจะเป็น ระวังคีย์ธรรมชาติมากถ้าคุณนำเข้าข้อมูลจากแหล่งอื่น!
HLGEM

2
หากคุณถูกขโมยข้อมูลประจำตัวคุณสามารถเปลี่ยนหมายเลขประกันสังคมของคุณได้ มีอีกสี่สถานการณ์ที่พวกเขาจะเปลี่ยนหมายเลขของคุณและพวกเขาจะปรากฏในเว็บไซต์ ssa.gov
Zvi Twersky

4

ฉันสงสัยว่าการบำบัดด้วยหนังสือพิมพ์แบบม้วนขึ้นของ Steven A. Lowe นั้นเป็นสิ่งจำเป็นสำหรับผู้ออกแบบโครงสร้างข้อมูลดั้งเดิม

นอกเหนือจากนั้นGUIDในฐานะคีย์หลักอาจเป็น Hog Performance ฉันจะไม่แนะนำที่นี่


2
การบอกว่ามันเป็นหมูที่มีประสิทธิภาพเป็นการปรับให้เหมาะสมก่อนเวลาอันควร Guids จำเป็นต้องใช้ในบางกรณี (ไคลเอ็นต์ที่ไม่ได้เชื่อมต่อ, การรวมตารางในอนาคต, การจำลองแบบ)
JC

2
"การเพิ่มประสิทธิภาพก่อนกำหนด" เป็นวลีที่ใช้มากเกินไปใน SO (IMHO)! ใช่อาจต้องใช้ GUID ในบางกรณี แต่ Andrew มีสิทธิ์ชี้ให้เห็นว่าไม่ควรใช้เป็นชนิดข้อมูลเริ่มต้นว่าจำเป็นหรือไม่
Tony Andrews

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

หรือใช้ทั้งสองอย่าง มีคีย์หลักแบบอิง / ยาวเพื่อการเลือกและเข้าร่วมอย่างรวดเร็วและมีเขตข้อมูล guid อย่างน้อยนั่นคือสิ่งที่ฉันทำ มันผิดหรือเปล่า? ฉันไม่ควรทำอย่างนั้นหรือ :)
Andrew Rollings

ฉันใช้ทั้งสองคอลัมน์ด้วย แต่ไม่แน่ใจว่ามันผิดหรือเปล่า คุณพบมัน @AndrewRollings หรือไม่?
YÒGÎ

3

คุณควรใช้คีย์หลัก 'คอมโพสิต' หรือ 'ผสม' ที่ประกอบด้วยหลายฟิลด์

นี่คือทางออกที่ดีที่สุดไปที่นี่เพื่อรับข้อมูลเพิ่มเติม :)


3

ฉันก็มักจะใช้คอลัมน์หมายเลขที่เป็นตัวเลข ใน oracle ฉันใช้หมายเลข (18,0) โดยไม่มีเหตุผลจริงเหนือจำนวน (12,0) (หรืออะไรก็ตามที่เป็น int มากกว่าความยาว) บางทีฉันแค่ไม่อยากกังวลเกี่ยวกับการรับแถวไม่กี่พันล้านแถว db!

ฉันยังรวมคอลัมน์ที่สร้างและปรับเปลี่ยน (การประทับเวลาชนิด) สำหรับการติดตามพื้นฐานซึ่งดูเหมือนว่ามีประโยชน์

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


2
ฉันต้องชี้ให้เห็นว่าฉันไม่ได้ใส่ ID ในตารางลิงค์ / เข้าร่วมเฉพาะในตารางที่มีข้อมูล
JeeBee

3

ฉันค้นหาคีย์หลักแบบธรรมชาติและใช้ในตำแหน่งที่ฉันสามารถทำได้

หากไม่พบคีย์ธรรมชาติฉันชอบ GUID ใน INT ++ เพราะ SQL Server ใช้ต้นไม้และมันก็ไม่ดีที่จะเพิ่มคีย์ลงในส่วนท้ายของต้นไม้เสมอ

ในตารางที่มีการเชื่อมต่อแบบหลายต่อหลายครั้งฉันใช้คีย์หลักแบบผสมของคีย์ต่างประเทศ

เพราะฉันโชคดีพอที่จะใช้ SQL Server ฉันสามารถศึกษาแผนการดำเนินการและสถิติด้วยตัวสร้างโปรไฟล์และตัววิเคราะห์คิวรีและค้นหาว่าคีย์ของฉันทำงานอย่างไรได้อย่างง่ายดายมาก


คุณมีเอกสารใดบ้างในการสำรองข้อมูลคำสั่งนี้: 'หากไม่พบคีย์ธรรมชาติฉันต้องการ GUID ใน INT ++ เพราะ SQL Server ใช้ต้นไม้และมันไม่ดีที่จะเพิ่มคีย์ลงในต้นไม้' ไม่น่าสงสัยเพียงแค่พยายามรวบรวมเอกสารบางอย่าง
Lloyd Cotten

1
@Lloyd - ดีใจที่คุณสนใจสิ่งที่ฉันพบว่าตัวเองมีเสน่ห์มาก จุดเริ่มต้นที่ดีที่msdn.microsoft.com/en-us/library/ms177443(SQL.90).aspx
Guge

2

ฉันมักจะใช้ฟิลด์หมายเลขอัตโนมัติหรือข้อมูลประจำตัว

ฉันทำงานให้กับลูกค้าที่ใช้ SSN เป็นคีย์หลักและเนื่องจากข้อบังคับ HIPAA ถูกบังคับให้เปลี่ยนเป็น "MemberID" และทำให้เกิดปัญหามากมายเมื่ออัปเดตคีย์ต่างประเทศในตารางที่เกี่ยวข้อง การยึดมาตรฐานคอลัมน์ที่สอดคล้องกันช่วยให้ฉันหลีกเลี่ยงปัญหาที่คล้ายกันในโครงการทั้งหมดของฉัน


6
การเลือกคีย์ธรรมชาติโดยนักพัฒนาไม่ดีไม่ได้หมายความว่าคีย์ธรรมชาติไม่ดี
Tom H

1
เครื่องมือที่ใช้งานยากไม่ใช่จุดที่เทียบกับเครื่องมือนั้นใช่ไหม
Sqeaky

1

ตารางทั้งหมดควรมีคีย์หลัก มิฉะนั้นสิ่งที่คุณมีก็คือฮีป - ในบางสถานการณ์นี้อาจเป็นสิ่งที่คุณต้องการ (มีการโหลดจำนวนมากเมื่อข้อมูลถูกจำลองแบบผ่านนายหน้าบริการไปยังฐานข้อมูลหรือตารางอื่นเป็นต้น)

สำหรับตารางการค้นหาที่มีจำนวนแถวน้อยคุณสามารถใช้รหัส 3 CHAR เป็นคีย์หลักเนื่องจากใช้พื้นที่น้อยกว่า INT แต่ความแตกต่างด้านประสิทธิภาพนั้นเล็กน้อย นอกเหนือจากนั้นฉันจะใช้ INT เสมอยกเว้นว่าคุณมีตารางอ้างอิงที่อาจมีคีย์หลักแบบประกอบที่ประกอบด้วยคีย์ต่างประเทศจากตารางที่เกี่ยวข้อง


1

หากคุณต้องการอ่านย้อนกลับไปในการอภิปรายแบบเก่า ๆ ทั้งหมดให้ค้นหา "คีย์ธรรมชาติ" ใน Stack Overflow คุณควรได้รับหน้าผลลัพธ์กลับมา


1

guid ของสามารถใช้เป็นคีย์หลักได้ แต่คุณต้องสร้างชนิดที่ถูกต้องของ GUID เพื่อให้ทำงานได้ดี

คุณต้องสร้าง COMB GUID บทความที่ดีเกี่ยวกับเรื่องนี้และสถิติประสิทธิภาพคือ ต้นทุนของ GUID เป็นคีย์หลักของเป็นคีย์หลัก

นอกจากนี้ยังมีโค้ดบางส่วนในการสร้าง guid ของหวีในSQLอยู่ในuniqueIdentifier เทียบกับตัวตน ( เก็บ )


5
IMHO, guid's ควรใช้เมื่อคุณต้องการซิงโครไนซ์ข้อมูลข้ามฐานข้อมูลเท่านั้น รหัสที่สร้างขึ้นโดยอัตโนมัติเป็นปัญหา ความแตกต่างระหว่างการใช้ guid และการใช้ชนิดตัวเลขพื้นฐานคือ guid จะต้องมี 16 ไบต์ต่อแถวในขณะที่ตัวเลขจะมีขนาดเล็กกว่ามาก
Logicalmind

หากคุณไปที่ลิงก์ที่ฉันให้ไว้ข้างต้นจะมีความแตกต่างเล็กน้อยในประสิทธิภาพการทำงานโดยใช้ COMB Guids
Donny V.

0

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


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

2
ฉันไม่ใหญ่โตหรอกที่จะเรียนรู้สิ่งใหม่ ฉันชอบที่จะเห็นตัวอย่างของสิ่งที่คุณพูดมันจะเป็นประโยชน์ในการฉีดข้อเท็จจริงที่มีเหตุผลเล็กน้อยเข้าไปในข้อโต้แย้งทางศาสนาเหล่านี้
Dan Blair

0

ฉันจะรู้ล่วงหน้าเกี่ยวกับความชอบของฉันสำหรับคีย์ธรรมชาติ - ใช้มันเท่าที่จะเป็นไปได้เพราะมันจะทำให้การจัดการฐานข้อมูลของคุณง่ายขึ้นมาก ฉันสร้างมาตรฐานใน บริษัท ของเราว่าตารางทั้งหมดมีคอลัมน์ต่อไปนี้:

  • ID แถว (GUID)
  • ผู้สร้าง (สตริง; มีค่าเริ่มต้นของชื่อผู้ใช้ปัจจุบัน ( SUSER_SNAME()ใน T-SQL))
  • สร้าง (DateTime)
  • การประทับเวลา

ID แถวมีคีย์ที่ไม่ซ้ำกันต่อตารางและในกรณีใด ๆ จะถูกสร้างขึ้นโดยอัตโนมัติต่อแถว (และการอนุญาตป้องกันไม่ให้มีใครแก้ไขได้) และรับประกันว่าจะไม่ซ้ำกันในทุกตารางและฐานข้อมูล หากระบบ ORM ใด ๆ จำเป็นต้องมีรหัส ID เดียวระบบจะใช้รหัสนี้

ในขณะเดียวกัน PK ที่แท้จริงคือถ้าเป็นไปได้เป็นกุญแจธรรมชาติ กฎภายในของฉันเป็นดังนี้:

  • ผู้คน - ใช้กุญแจตัวแทนเช่น INT หากเป็นภายในผู้ใช้ Active Directory GUID เป็นตัวเลือกที่ยอมรับได้
  • ตารางการค้นหา (เช่น StatusCodes) - ใช้รหัสสั้น ๆ มันง่ายต่อการจดจำได้มากกว่า INT และในหลาย ๆ กรณีแบบฟอร์มกระดาษและผู้ใช้จะใช้เพื่อความกะทัดรัด (เช่นสถานะ = "E" สำหรับ "หมดอายุ", "A" สำหรับ "อนุมัติ", "NADIS" สำหรับ "ไม่มีใยหินที่ตรวจพบ ในตัวอย่าง ")
  • ตารางเชื่อมโยง - การรวมกันของ FK (เช่นEventId, AttendeeId)

ดังนั้นคุณจะต้องจบลงด้วย PK ธรรมชาติที่มนุษย์อ่านได้และน่าจดจำและ GUID ที่เป็นมิตรต่อหนึ่งตาราง ORM

Caveat: ฐานข้อมูลที่ฉันเก็บมีแนวโน้มที่จะมีการบันทึกมากกว่า 100,000 รายการมากกว่าล้านหรือหลายพันล้านรายการดังนั้นหากคุณมีประสบการณ์เกี่ยวกับระบบที่ใหญ่กว่าซึ่งห้ามใช้คำแนะนำของฉันอย่าลังเลที่จะเพิกเฉยต่อฉัน!


1
คุณแนะนำให้สร้างทั้งสองGUID และ INT SK สำหรับตารางที่ไม่มีคีย์ธรรมชาติที่แข็งแรงหรือไม่?

คุณไม่จำเป็นต้องทำ แต่ข้อดีคือ: a) การทำแบบจำลองทำได้ง่ายขึ้นถ้าคุณต้องการ b) เมื่อจัดการกับ ORM คุณสามารถกำหนด ID เฉพาะให้กับวัตถุของคุณในรหัสก่อนที่จะบันทึก (ซึ่งมีประโยชน์ถ้าคุณ ต้องแก้ไขจำนวนมากบนวัตถุของคุณอาจบันทึกลงในแคชเซสชันก่อนที่จะบันทึก) กุญแจสำคัญคือ INT ในอินสแตนซ์นี้ GUID เป็นเพียงโบนัส
Keith Williams
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.