ทำไมคนไม่แนะนำให้ใช้ชื่อ“ Id” สำหรับคอลัมน์ข้อมูลประจำตัว


68

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

ฉันเคยเห็นคนแนะนำคำนำหน้าIdด้วยชื่อตาราง แต่ดูเหมือนว่าจะทำให้การทำงานมากขึ้นสำหรับผู้ที่เขียนคำสั่ง SQL (หรือโปรแกรมเมอร์ถ้าคุณใช้ ORM เช่น Entity Framework) โดยเฉพาะชื่อตารางที่ยาวขึ้นเช่นCustomerProductIdหรือAgencyGroupAssignementId

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

เหตุใดผู้คนจึงไม่แนะนำให้ใช้ชื่อIdสำหรับคอลัมน์ข้อมูลประจำตัว

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

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


10
BF bunfight ที่นี่แล้ว: programmers.stackexchange.com/q/114728/5905พวกเราหลายคน (อ่าน: ฉัน) ถูกดูดเข้าไป ...
gbn

มีกฎดังกล่าวต่อต้านการใช้ "id" เป็นชื่อของคอลัมน์ข้อมูลประจำตัวหรือไม่ ActiveRecord ซึ่งเป็นมาตรฐาน ORM สำหรับ Ruby on Rails ทำเช่นนั้นโดยการประชุม ar.rubyonrails.org
200_success

1
@ 200_success ที่ระดับฐานข้อมูลใช่ นี่เป็นเว็บไซต์ฐานข้อมูลไม่ใช่เว็บไซต์ ORM;)
JNK

2
นอกจากนี้สำหรับ SQL Server โดยเฉพาะให้ดูที่dba.stackexchange.com/questions/124655/ …และโดยเฉพาะอย่างยิ่งconnect.microsoft.com/SQLServer/feedback/details/2178150
Aaron Bertrand

คำตอบ:


46

คำนำหน้าชื่อตารางมีเหตุผลที่ดีมาก

พิจารณา:

TableA (id int identity, stringdata varchar(max))

TableB (id int identity, stringdata varchar(max))

เราต้องการDELETEจากTableAบันทึกที่มีอยู่ในทั้งสองตาราง ง่ายพอเราจะทำINNER JOIN:

DELETE a
FROM 
  TableA A
INNER JOIN 
  TableB B
    ON b.id = B.id

.... และเราก็เช็ดออกทั้งหมดของ TableA เราเปรียบเทียบ ID ของ B กับตัวเองโดยไม่ได้ตั้งใจ - ทุกระเบียนที่ตรงกันและทุกระเบียนถูกลบ

หากมีการตั้งชื่อฟิลด์TableAIdและTableBIdสิ่งนี้จะเป็นไปไม่ได้ ( Invalid field name TableAid in TableB)

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

นอกจากนี้ยังทำให้มันชัดเจนมากที่มาจากเขตข้อมูลในการสืบค้นยาวที่มีจำนวนมากJOINs


10
ดังนั้นจึงเป็นหลักการตั้งชื่อเพื่อป้องกันข้อผิดพลาด? ฉันคิดว่าการใช้begin transactionและcommit transactionจะเป็นการฝึกฝนที่ดีกว่าการใช้ (imo) แผนการตั้งชื่อที่น่ารังเกียจมากขึ้น
ราเชล

13
@Rachel: มันสำหรับ 1. ความชัดเจน 2. หลีกเลี่ยงการนามแฝงคอลัมน์ที่ไม่จำเป็น 3. อนุญาตให้ JOIN..USING 4. รบกวนลิง PHP ที่ทำงานในวัตถุเดียวชุดไม่ได้
GBN

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

7
@Andy ฉันมักจะทำSELECTเพื่อค้นหาบันทึกของฉันก่อนที่จะเรียกใช้DELETEและเมื่อฉันเรียกใช้คำสั่งที่ฉันมักจะตรวจสอบว่าการนับแถวเป็นสิ่งที่ฉันคาดหวังก่อนที่จะกระทำ
ราเชล

5
@ ราเชลดีจังที่คุณมีบางอย่างที่เหมาะกับคุณ คุณทำให้ทุกคนทำอย่างนั้นได้ไหม
แอนดี้

36

ส่วนใหญ่เป็นการป้องกันไม่ให้กุญแจต่างประเทศกลายเป็นความเจ็บปวดอันยิ่งใหญ่ สมมติว่าคุณมีสองตาราง: ลูกค้าและ CustomerAddress คีย์หลักสำหรับทั้งสองคือคอลัมน์ชื่อ id ซึ่งเป็นคอลัมน์ข้อมูลประจำตัว (int)

ตอนนี้คุณต้องมีรหัสลูกค้าอ้างอิงจาก CustomerAddress คุณไม่สามารถตั้งชื่อรหัสคอลัมน์ได้ดังนั้นคุณจะไปกับ customer_id

สิ่งนี้นำไปสู่ปัญหาสองสามข้อ ก่อนอื่นคุณต้องจำอย่างสม่ำเสมอว่าจะต้องเรียกคอลัมน์ "id" เมื่อใดและจะเรียกว่า "customer_id" และถ้าคุณทำสิ่งนี้ผิดพลาดมันจะนำไปสู่ปัญหาที่สอง หากคุณมีคำถามจำนวนมากที่มีการรวมโหลหรือมากกว่านั้นและจะไม่ส่งคืนข้อมูลใด ๆ ให้สนุกกับการเล่น Where's Waldo และตามล่าตัวพิมพ์นี้:

ON c.id = ca.id

ON c.id = ca.customer_idอ๊ะควรจะได้รับ หรือดีกว่าให้ตั้งชื่อคอลัมน์ข้อมูลประจำตัวของคุณอย่างละเอียดเพื่อให้เป็นON c.customer_id = ca.customer_idไปได้ จากนั้นหากคุณใช้นามแฝงของตารางที่ไม่ถูกต้องโดยไม่ตั้งใจอยู่ที่ไหนสักแห่ง customer_id จะไม่เป็นคอลัมน์ในตารางนั้นและคุณจะได้รับข้อผิดพลาดในการรวบรวมที่ดีแทนที่จะเป็นผลลัพธ์ที่ว่างเปล่า

ได้รับแล้วมีหลายกรณีที่สิ่งนี้ไม่ได้ช่วยเช่นถ้าคุณต้องการความสัมพันธ์กับต่างประเทศที่สำคัญจากตารางหนึ่งไปยังอีกตารางเดียว แต่การตั้งชื่อคีย์หลักทั้งหมด "id" ไม่ได้ช่วยอะไรเลย


27

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

  • ข้อผิดพลาดน้อยลงเนื่องจากฟิลด์ตัวตนไม่ได้ตั้งชื่อเหมือนกัน

    คุณไม่สามารถผิดพลาดเขียนแบบสอบถามที่ร่วมในB.Id = B.IdแทนA.Id = B.Idเพราะสาขาที่ตัวตนจะไม่ได้รับการตั้งชื่อเดียวกันแน่นอน

  • ชื่อคอลัมน์ที่ชัดเจนขึ้น

    หากคุณดูที่ชื่อคอลัมน์CustomerIdคุณจะรู้ทันทีว่าข้อมูลใดอยู่ในคอลัมน์นั้น หากชื่อคอลัมน์เป็นชื่อสามัญเช่นIdคุณต้องทราบชื่อตารางและต้องทราบว่าข้อมูลในคอลัมน์ใดมี

  • หลีกเลี่ยงชื่อแทนคอลัมน์ที่ไม่จำเป็น

    ตอนนี้คุณสามารถเขียนSELECT CustomerId, ProductIdจากแบบสอบถามที่เชื่อมต่อCustomersกับProductsแทนที่จะเป็นSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • อนุญาตให้ใช้JOIN..USINGไวยากรณ์

    คุณสามารถเข้าร่วมตารางด้วยไวยากรณ์Customer JOIN Products USING (CustomerId)แทนCustomer JOIN Products ON Customer.Id = Products.Id

  • คีย์ค้นหาได้ง่ายกว่าในการค้นหา

    หากคุณกำลังมองหาเขตข้อมูลตัวตนของลูกค้าในโซลูชันขนาดใหญ่การค้นหาCustomerIdนั้นมีประโยชน์มากกว่าการค้นหาId

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

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


12

หากต้องการคัดลอกคำตอบของฉันจากคำถามที่เชื่อมโยง:

มีสถานการณ์ที่การติด "ID" ในทุกตารางไม่ใช่ความคิดที่ดีที่สุด: USINGคำหลักหากได้รับการสนับสนุน เราใช้บ่อยใน MySQL

ตัวอย่างเช่นหากคุณมีfooTableคอลัมน์fooTableIdและbarTableคีย์ต่างประเทศfooTableIdคุณสามารถสร้างคิวรีของคุณเช่น:

SELECT fooTableId, fooField1, barField2 FROM fooTable INNER JOIN barTable USING (fooTableId)

ไม่เพียงบันทึกการพิมพ์ แต่สามารถอ่านได้มากกว่าเมื่อเปรียบเทียบกับตัวเลือกอื่น ๆ :

SELECT fooTable.Id, fooField1, barField2 FROM fooTable INNER JOIN barTable ON (fooTable.Id = barTable.foTableId)

9

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

ตัวอย่างเช่นฐานข้อมูลสำหรับบล็อกอาจมีลักษณะเช่นนี้ในรูปแบบที่ผิดปกติโดยสมมติว่ามีข้อ จำกัด ที่ไม่เหมือนใครใน Author_Nickname

| Author_Nickname | Author_Email | Post_Title | Post_Body |
+-----------------+--------------+------------+-----------+
| dave            | dave@x.com   | Blah       | Bla bla   |
| dave            | dave@x.com   | Stuff      | I like    |
| sophie          | s@oph.ie     | Lorem      | Ipsum     |

การทำให้เป็นมาตรฐานมันจะให้สองตาราง:

ผู้แต่ง:

| Author_Nickname | Author_Email |
+-----------------+--------------+
| dave            | dave@x.com   |
| sophie          | s@oph.ie     |

เสา

| Author_Nickname | Post_Title | Post_Body |
+-----------------+------------+-----------+
| dave            | Blah       | Bla bla   |
| dave            | Stuff      | I like    |
| sophie          | Lorem      | Ipsum     |

ที่นี่ Author_Nickname จะเป็นคีย์หลักสำหรับตารางผู้แต่งและคีย์ต่างประเทศในตารางโพสต์ แม้ว่า Author_Nickname จะปรากฏในตารางที่สองก็ยังคงสอดคล้องกับหน่วยข้อมูลเดียวคือ ชื่อคอลัมน์แต่ละสอดคล้องกับเขตข้อมูลเดียว

ในหลายกรณีมีข้อ จำกัด ที่ไม่ซ้ำกันในเขตข้อมูลเดิมดังนั้นเขตข้อมูลตัวเลขจะถูกใช้เป็นคีย์หลักแทน สิ่งนี้จะไม่เปลี่ยนความจริงที่ว่าแต่ละชื่อคอลัมน์ยังคงแสดงถึงเขตข้อมูลเดียว ในการออกแบบฐานข้อมูลแบบดั้งเดิมชื่อคอลัมน์แต่ละชื่อจะตรงกับเขตข้อมูลเดียวแม้ว่าจะไม่ใช่คีย์ก็ตาม (เช่นหนึ่งจะใช้part.partnameและclient.clientnameมากกว่าpart.nameและclient.name ) นี่คือเหตุผลสำหรับการมีอยู่ของINNER JOIN ... USING <key>และNATURAL JOINไวยากรณ์

อย่างไรก็ตามทุกวันนี้และด้วยเลเยอร์ ORM ที่พร้อมใช้งานในหลายภาษาฐานข้อมูลมักจะถูกออกแบบให้เป็นเลเยอร์แบบถาวรสำหรับภาษา OO ซึ่งเป็นเรื่องธรรมดาที่ตัวแปรที่มีบทบาทเดียวกันในคลาสที่แตกต่างกันจะเรียกว่าเหมือนกัน ( part.nameและclient.nameไม่ใช่part.partnameและclient.clientname ) ในบริบทดังกล่าวฉันมักจะใช้ 'ID' สำหรับคีย์หลักของฉัน


7

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

การใช้ "Ident" แทน "Id" นั้นไม่ได้แก้ปัญหาอะไรเลยหากการใช้ "Ident" จบลงที่ทุกตาราง

มีบทความที่ดีเกี่ยวกับข้อตกลงการเข้ารหัส SQL บนไซต์ Drupalที่บ่งบอกถึงแนวปฏิบัติที่ดีสำหรับสถานการณ์นี้:

เป็นแนวปฏิบัติที่ดีที่จะนำหน้าชื่อตารางด้วยชื่อโมดูลเพื่อป้องกันความขัดแย้งของเนมสเปซที่เป็นไปได้

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


7

ฉันตั้งชื่อคอลัมน์ CustomerID แทน ID ดังนั้นทุกครั้งที่ฉันพิมพ์

FROM dbo.Customers AS c JOIN dbo.CustomerOrders AS o

SQL Prompt จะแนะนำสิ่งต่อไปนี้ทันที

ON c.CustomerID = o.CustomerID 

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


5

เป็นเหตุผลเดียวกันว่าทำไมคุณไม่ตั้งชื่อเขตข้อมูล varchar ทั้งหมดเช่น "UserText" และ "UserText1" หรือทำไมคุณไม่ใช้ "UserDate" และ "UserDate1"

โดยทั่วไปถ้าคุณมีเขตข้อมูลตัวตนในตารางมันเป็นคีย์หลักของคุณ คุณจะสร้างตารางลูกด้วย foreign key ไปยังตารางหลักได้อย่างไรถ้าคีย์หลักในทั้งสองตารางเป็น id

ไม่ใช่ทุกคนที่เห็นด้วยกับวิธีการนี้ แต่ในฐานข้อมูลของฉันฉันจะกำหนดตัวย่อเฉพาะให้แต่ละตาราง PK สำหรับตารางนั้นจะมีชื่อว่า PK_ [abbrv] ID ถ้ามันถูกใช้เป็น FK ทุกที่ฉันจะใช้ FK_ [abbrv] ID ตอนนี้ฉันไม่มีเดาเลยว่าจะหาความสัมพันธ์ของตารางได้อย่างไร


5

โดยพื้นฐานแล้วด้วยเหตุผลเดียวกันกับที่คุณไม่ได้ตั้งชื่อพารามิเตอร์ parameter1, parameter2 ... มันถูกต้อง แต่ไม่ใช่คำอธิบาย หากคุณเห็น TableId คุณอาจคิดได้อย่างปลอดภัยว่าจะใช้เพื่อเก็บ pk สำหรับ Table โดยไม่คำนึงถึงบริบท

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

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


3

ใช้คำนำหน้าเพื่อให้ชื่อเดียวกันสามารถนำมาใช้ทั้งในคีย์หลักและบริบทที่สำคัญต่างประเทศเพื่อให้คุณสามารถดำเนินการ/natural joinjoin ... using

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