Tại sao mọi người khuyên bạn không nên sử dụng tên Id Idio cho một cột danh tính?


68

Tôi được dạy không sử dụng tên Idcho cột nhận dạng của các bảng của mình, nhưng gần đây tôi chỉ sử dụng nó bởi vì nó đơn giản, ngắn gọn và rất mô tả về dữ liệu thực sự là gì.

Tôi đã thấy mọi người đề xuất tiền tố Idvới tên bảng, nhưng điều này dường như giúp làm việc nhiều hơn cho người viết các truy vấn SQL (hoặc lập trình viên nếu bạn đang sử dụng ORM như Entity Framework), đặc biệt là các tên bảng dài hơn như CustomerProductIdhoặc làAgencyGroupAssignementId

Một nhà cung cấp bên thứ ba mà chúng tôi thuê để tạo ra thứ gì đó cho chúng tôi thực sự đặt tên cho tất cả các cột nhận dạng của họ Identchỉ để tránh sử dụng Id. Lúc đầu, tôi nghĩ rằng họ đã làm điều đó bởi vì đó Idlà một từ khóa, nhưng khi tôi nhìn vào nó, tôi thấy đó Idkhông phải là một từ khóa trong SQL Server 2005, đó là những gì chúng ta đang sử dụng.

Vậy tại sao mọi người khuyên không nên sử dụng tên Idcho một cột danh tính?

Chỉnh sửa: Để làm rõ, tôi không hỏi nên sử dụng quy ước đặt tên nào, hoặc cho các đối số sử dụng một quy ước đặt tên khác. Tôi chỉ muốn biết lý do tại sao không nên sử dụng Idcho tên cột nhận dạng.

Tôi là một lập trình viên duy nhất, không phải là một dba và với tôi cơ sở dữ liệu chỉ là nơi lưu trữ dữ liệu của tôi. Vì tôi thường xây dựng các ứng dụng nhỏ và thường sử dụng ORM để truy cập dữ liệu, nên một tên trường chung cho trường nhận dạng sẽ dễ làm việc hơn nhiều. Tôi muốn biết những gì tôi đang bỏ lỡ bằng cách làm điều này, và nếu có bất kỳ lý do thực sự tốt cho tôi để không làm điều này.


10
BF bunfight đây đã: programmers.stackexchange.com/q/114728/5905 Một số người trong chúng ta (đọc: me) đã bị hút vào nó ...
GBN

Có thực sự có một quy tắc chống lại việc sử dụng "id" làm tên của cột định danh không? ActiveRecord, ORM tiêu chuẩn cho Ruby on Rails, thực hiện chính xác điều đó theo quy ước. ar.rubyonrails.org
200_success

1
@ 200_success Ở cấp độ cơ sở dữ liệu, có. Đây là trang web cơ sở dữ liệu, không phải trang ORM;)
JNK

2
Ngoài ra, đối với SQL Server cụ thể, hãy xem dba.stackexchange.com/questions/124655/ , và cụ thể hơn, connect.microsoft.com/QueryServer/feedback/details/2178150
Aaron Bertrand

Câu trả lời:


46

Tiền tố tên bảng có lý do rất tốt.

Xem xét:

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

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

Chúng tôi muốn DELETEtừ TableAcác bản ghi tồn tại trong cả hai bảng. Đủ dễ dàng, chúng tôi sẽ chỉ làm một INNER JOIN:

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

.... và chúng tôi vừa xóa sạch tất cả TableA. Chúng tôi vô tình so sánh ID của B với chính nó - mọi bản ghi khớp và mọi bản ghi đều bị xóa.

Nếu các trường đã được đặt tên TableAIdTableBIdđiều này là không thể ( Invalid field name TableAid in TableB).

Cá nhân tôi không có vấn đề gì với việc sử dụng tên idtrong bảng, nhưng thực sự tốt hơn là đặt tên trước bằng tên bảng (hoặc tên thực thể, nếu TableAlà người thì PeopleIdcũng sẽ hoạt động tốt) để tránh vô tình so sánh với trường sai và thổi một cái gì đó lên

Điều này cũng làm cho nó rất rõ ràng nơi các trường đến từ các truy vấn dài với nhiều JOINs.


10
Vì vậy, về cơ bản nó là một quy ước đặt tên để bảo vệ chống lại lỗi? Tôi nghĩ rằng việc sử dụng begin transactioncommit transactionsẽ tốt hơn so với việc sử dụng (imo) một kế hoạch đặt tên đáng ghét hơn
Rachel

13
@Rachel: đó là 1. rõ ràng 2. tránh các bí danh cột không cần thiết 3. cho phép THAM GIA..USING 4. làm phiền những con khỉ PHP làm việc trong các đối tượng đơn lẻ, không đặt
gbn

4
@Rachel Nếu bạn không nhận thấy lỗi khi viết truy vấn và ngay trước khi bạn thực hiện nó, bạn sẽ không nhận ra lỗi đó trước khi cam kết. Điều này xảy ra, tại sao làm cho nó có nhiều khả năng?
Andy

7
@Andy Tôi luôn luôn làm một SELECTđể tìm hồ sơ của mình trước khi tôi chạy DELETE, và một khi tôi chạy câu lệnh, tôi luôn xác minh rằng số hàng là những gì tôi mong đợi trước khi cam kết.
Rachel

5
@Rachel Thật tuyệt khi bạn có thứ gì đó phù hợp với mình. Bạn có thể làm cho tất cả mọi người làm điều đó?
Andy

36

Chủ yếu là để giữ cho các khóa ngoại không trở thành một nỗi đau rất lớn. Giả sử bạn có hai bảng: Khách hàng và Khách hàng. Khóa chính cho cả hai là một cột có tên id, là một cột nhận dạng (int).

Bây giờ bạn cần phải có ID khách hàng được tham chiếu từ CustomerAddress. Rõ ràng, bạn không thể đặt tên cho id cột, vì vậy bạn đi cùng với customer_id.

Điều này dẫn đến một vài vấn đề. Đầu tiên, bạn phải luôn nhớ khi nào gọi cột là "id" và khi nào gọi nó là "customer_id". Và nếu bạn làm hỏng điều này, nó sẽ dẫn đến vấn đề thứ hai. Nếu bạn có một truy vấn lớn với hàng tá tham gia và không trả lại bất kỳ dữ liệu nào, hãy vui vẻ chơi Waldo ở đâu và săn lùng lỗi đánh máy này:

ON c.id = ca.id

Rất tiếc, lẽ ra phải có ON c.id = ca.customer_id. Hoặc tốt hơn nữa, đặt tên cho các cột danh tính của bạn một cách mô tả, để nó có thể ON c.customer_id = ca.customer_id. Sau đó, nếu bạn vô tình sử dụng bí danh bảng sai ở đâu đó, customer_id sẽ không phải là một cột trong bảng đó và bạn sẽ gặp một lỗi biên dịch tốt, thay vì kết quả trống và nheo mã tiếp theo.

Cấp, có những trường hợp điều này không có ích, chẳng hạn như nếu bạn cần nhiều mối quan hệ khóa ngoại từ bảng này sang bảng khác, nhưng việc đặt tên cho tất cả các khóa chính "id" cũng không giúp được gì cả.


27

Dưới đây là tóm tắt tất cả các câu trả lời về những lợi thế thu được từ quy ước để không sử dụng tên chung cho tất cả các khóa chính:

  • Ít sai lầm hơn, vì các trường danh tính không được đặt tên giống nhau

    Bạn không thể viết nhầm một truy vấn tham gia B.Id = B.Idthay vì A.Id = B.Id, vì các trường danh tính sẽ không bao giờ được đặt tên chính xác.

  • Tên cột rõ ràng hơn.

    Nếu bạn nhìn vào một cột có tên CustomerId, bạn sẽ biết ngay dữ liệu nào trong cột đó. Nếu tên cột giống như tên chung Id, thì bạn cũng cần biết tên bảng để biết dữ liệu mà cột chứa.

  • Tránh các bí danh cột không cần thiết

    Bây giờ bạn có thể viết SELECT CustomerId, ProductIdtừ một truy vấn mà tham gia Customersvới Products, thay vìSELECT Customer.Id as CustomerId, Products.Id as ProductId

  • Cho phép JOIN..USINGcú pháp

    Bạn có thể nối các bảng với cú pháp Customer JOIN Products USING (CustomerId), thay vìCustomer JOIN Products ON Customer.Id = Products.Id

  • Chìa khóa dễ tìm thấy hơn trong các tìm kiếm

    Nếu bạn đang tìm kiếm lĩnh vực nhận dạng của khách hàng trong một giải pháp lớn, tìm kiếm CustomerIdsẽ hữu ích hơn nhiều so với tìm kiếmId

Nếu bạn có thể nghĩ ra bất kỳ lợi thế nào khác mà quy ước đặt tên này có, hãy cho tôi biết và tôi sẽ thêm nó vào danh sách.

Cho dù bạn chọn sử dụng tên cột duy nhất hoặc giống hệt nhau cho các trường danh tính là tùy thuộc vào bạn, nhưng bất kể bạn chọn gì, vui lòng nhất quán :)


12

Để sao chép câu trả lời của tôi từ câu hỏi được liên kết:

Có một tình huống mà việc dán "ID" trên mỗi bảng không phải là ý tưởng tốt nhất: USINGtừ khóa, nếu nó được hỗ trợ. Chúng tôi sử dụng nó thường xuyên trong MySQL.

Ví dụ: nếu bạn có fooTablecột fooTableIdbarTablekhóa ngoại fooTableId, thì các truy vấn của bạn có thể được xây dựng như sau:

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

Nó không chỉ tiết kiệm gõ, mà còn dễ đọc hơn nhiều so với cách thay thế:

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

9

Sau khi bình thường hóa một lược đồ cơ sở dữ liệu để hạn chế sự dư thừa, các bảng được chia thành các bảng nhỏ hơn với các mối quan hệ được thiết lập (từ một đến một, nhiều đến nhiều, nhiều đến nhiều). Trong quy trình, các trường đơn trong bảng gốc có thể xuất hiện trong nhiều bảng được chuẩn hóa.

Ví dụ, một cơ sở dữ liệu cho một blog có thể trông như thế này ở dạng không chuẩn hóa, giả sử một ràng buộc duy nhất trên 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     |

Bình thường hóa nó sẽ mang lại hai bảng:

Tác giả:

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

Bài đăng

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

Ở đây Author_Nickname sẽ là khóa chính cho bảng tác giả và khóa ngoại trong bảng bài. Ngay cả khi Author_Nickname xuất hiện trong hai bảng, nó vẫn tương ứng với một đơn vị thông tin, nghĩa là. mỗi tên cột tương ứng với một trường duy nhất .

Trong nhiều trường hợp, không thể có một ràng buộc duy nhất trên các trường ban đầu, do đó, một trường nhân tạo số được sử dụng làm khóa chính thay thế. Điều này không thay đổi thực tế là mỗi tên cột vẫn đại diện cho một trường duy nhất. Trong thiết kế cơ sở dữ liệu truyền thống, các tên cột riêng lẻ tương ứng với các trường đơn lẻ ngay cả khi chúng không có khóa. (ví dụ: người ta sẽ sử dụng part.partnameclient.clientname thay vì part.nameclient.name ). Đây là lý do cho sự tồn tại của INNER JOIN ... USING <key>và các NATURAL JOINcú pháp.

Tuy nhiên, ngày nay và với các lớp ORM có sẵn trong nhiều ngôn ngữ, cơ sở dữ liệu thường được thiết kế như một lớp bền vững cho các ngôn ngữ OO, trong đó, điều tự nhiên là các biến có cùng vai trò trong các lớp khác nhau được gọi là giống nhau ( part.nameclient.name , không phải part.partnameclient.clientname ). Trong ngữ cảnh như vậy, tôi có xu hướng sử dụng 'ID' cho các khóa chính của mình.


7

Một nhà cung cấp bên thứ ba mà chúng tôi đã thuê để tạo một cái gì đó cho chúng tôi thực sự đặt tên cho tất cả các cột nhận dạng của họ Nhận dạng chỉ để tránh sử dụng Id.

Sử dụng "Nhận dạng" thay vì "Id" không thực sự giải quyết được bất cứ điều gì nếu cuối cùng "Nhận dạng" được sử dụng trên tất cả các bảng của họ.

Có một bài viết hay về các quy ước mã hóa SQL trên trang web Drupal chỉ ra một thực tiễn tốt cho tình huống này:

Đó là một thực tiễn tốt để đặt tiền tố tên bảng với tên mô-đun để ngăn ngừa xung đột không gian tên có thể.

Từ quan điểm này, Khách hàng ProducttId và AgencygroupAss queId có ý nghĩa để sử dụng. Vâng, nó khá dài dòng. Bạn có thể rút ngắn nó, nhưng điểm quan trọng nhất cần quan tâm là liệu nhà phát triển theo dõi bạn có hiểu ý của bạn hay không . Các id được mở đầu bằng tên bảng dài dòng không nên để lại sự mơ hồ về những gì chúng là. Và (với tôi) điều đó quan trọng hơn việc lưu một vài tổ hợp phím.


7

Tôi đặt tên cột của mình là ID khách hàng thay vì ID, vì vậy bất cứ khi nào tôi nhập

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

SQL Prompt ngay lập tức gợi ý những điều sau đây

ON c.CustomerID = o.CustomerID 

Nó tiết kiệm cho tôi một vài tổ hợp phím. Tuy nhiên, tôi nghĩ rằng các quy ước đặt tên rất chủ quan và vì vậy tôi không có ý kiến ​​mạnh mẽ theo cách này hay cách khác.


5

Đó là cùng một lý do tại sao bạn sẽ không đặt tên cho tất cả các trường varchar của mình một cái gì đó như "UserText" và "UserText1" hoặc tại sao bạn sẽ không sử dụng "UserDate" và "UserDate1".

Điển hình nếu bạn có trường nhận dạng trong bảng, đó là khóa chính của bạn. Làm thế nào bạn có thể xây dựng một bảng con có khóa ngoại thành bảng cha nếu khóa chính trong cả hai bảng là id?

Không phải ai cũng đồng ý với phương thức này, nhưng trong cơ sở dữ liệu của tôi, tôi chỉ định một chữ viết tắt duy nhất cho mỗi bảng. PK cho bảng đó sẽ được đặt tên ID PK_ [abbrv]. NẾU được sử dụng làm FK ở bất cứ đâu thì tôi sẽ sử dụng ID FK_ [abbrv]. Bây giờ tôi không có công việc đoán nào để tìm ra các mối quan hệ bảng là gì.


5

Về cơ bản với cùng một lý do bạn thường không đặt tên tham số tham số1, tham số2 ... nó chính xác, nhưng không mô tả. Nếu bạn thấy TableId, thì có lẽ bạn có thể giả định rằng nó được sử dụng để giữ pk cho Bảng, bất kể bối cảnh.

Đối với bất kỳ ai đã sử dụng Danh tính, anh ta hoàn toàn bỏ lỡ vấn đề, đưa ra lựa chọn giữa Id và Id sử dụng Id. Nhận dạng thậm chí còn khó hiểu hơn Id.

Ngoài ngữ cảnh, Id có thể được coi là khóa chính của một số bảng (không cực kỳ hữu ích trừ khi id là hướng dẫn), nhưng Nhận dạng thậm chí không cho bạn biết (hoặc ít nhất là tôi) điều đó. Cuối cùng tôi sẽ nhận ra rằng Nhận dạng là viết tắt của danh tính (cách này hay cách khác), nhưng thời gian tôi dành để tìm ra rằng sẽ bị lãng phí.


3

Sử dụng tiền tố để có thể sử dụng cùng tên trong cả bối cảnh khóa chính và khóa ngoài, để bạn có thể thực hiện natural join/ join ... using.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.