2009-05-29 22 views
14

Tôi hiện đang trong quá trình thiết kế các bảng cơ sở dữ liệu cho ứng dụng quản lý trang web & của khách hàng. Câu hỏi của tôi là liên quan đến việc sử dụng các khóa chính như các phần chức năng của một bảng (và không gán các số "ID" cho mỗi bảng chỉ vì).Thiết kế cơ sở dữ liệu và việc sử dụng các khóa chính không phải là số

Ví dụ, đây là bốn bảng có liên quan từ cơ sở dữ liệu cho đến nay, một trong số đó sử dụng số khóa chính truyền thống, những người khác mà sử dụng tên độc đáo như khóa chính:

-- 
-- website 
-- 
CREATE TABLE IF NOT EXISTS `website` (
    `name` varchar(126) NOT NULL, 
    `client_id` int(11) NOT NULL, 
    `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP, 
    `notes` text NOT NULL, 
    `website_status` varchar(26) NOT NULL, 
    PRIMARY KEY (`name`), 
    KEY `client_id` (`client_id`), 
    KEY `website_status` (`website_status`), 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

-- 
-- website_status 
-- 
CREATE TABLE IF NOT EXISTS `website_status` (
    `name` varchar(26) NOT NULL, 
    PRIMARY KEY (`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
INSERT INTO `website_status` (`name`) VALUES 
('demo'), 
('disabled'), 
('live'), 
('purchased'), 
('transfered'); 

-- 
-- client 
-- 
CREATE TABLE IF NOT EXISTS `client` (
    `id` int(11) NOT NULL auto_increment, 
    `date_created` timestamp NOT NULL default CURRENT_TIMESTAMP, 
    `client_status` varchar(26) NOT NULL, 
    `firstname` varchar(26) NOT NULL, 
    `lastname` varchar(46) NOT NULL, 
    `address` varchar(78) NOT NULL, 
    `city` varchar(56) NOT NULL, 
    `state` varchar(2) NOT NULL, 
    `zip` int(11) NOT NULL, 
    `country` varchar(3) NOT NULL, 
    `phone` text NOT NULL, 
    `email` varchar(78) NOT NULL, 
    `notes` text NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `client_status` (`client_status`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; 

-- 
-- client_status 
--- 
CREATE TABLE IF NOT EXISTS `client_status` (
    `name` varchar(26) NOT NULL, 
    PRIMARY KEY (`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

INSERT INTO `client_status` (`name`) VALUES 
('affiliate'), 
('customer'), 
('demo'), 
('disabled'), 
('reseller'); 

Như bạn có thể nhìn thấy , 3 trong số 4 bảng sử dụng 'tên' của họ làm khóa chính. Tôi biết rằng những điều này sẽ luôn là duy nhất. Trong 2 trường hợp (bảng * _status) về cơ bản tôi đang sử dụng thay thế động cho ENUM, vì tùy chọn trạng thái có thể thay đổi trong tương lai và đối với bảng 'trang web', tôi biết rằng 'tên' của trang web sẽ luôn là duy nhất.

Tôi tự hỏi nếu đây là logic âm thanh, loại bỏ ID của bảng khi tôi biết tên luôn là số nhận dạng duy nhất hoặc công thức cho thảm họa? Tôi không phải là một DBA dày dạn nên bất kỳ phản hồi, phê bình, vv sẽ cực kỳ hữu ích.

Cảm ơn bạn đã dành thời gian đọc nội dung này!

+12

Chào mừng bạn đến với một cuộc chiến tranh thánh đã được tiến hành từ trước khi bạn được sinh ra. :) –

+3

Trên một lưu ý nghiêm túc hơn, một điều bạn sẽ phải xem xét là tác động của một cột VARCHAR trong một chỉ mục. Tôi không phải là một DBA dày dạn, vì vậy tôi không biết câu trả lời. Nhưng tôi khuyên bạn nên điền vào một bảng thử nghiệm, sử dụng một VARCHAR cho một khóa chính, với một vài triệu bản ghi và làm một số thử nghiệm. Sau đó, làm tương tự với một INT là khóa chính và xem những gì sẽ xảy ra. –

+0

Jordan là đúng về việc quan tâm đến một khóa "rộng" như một varchar (126). Xem câu trả lời của tôi dưới đây. – BradC

Trả lời

16

Có 2 lý do tôi sẽ luôn luôn thêm một số ID để một bảng tra cứu/ENUM:

  1. Nếu bạn đang tham khảo một bảng cột duy nhất với tên thì bạn có thể được phục vụ tốt hơn bằng cách sử dụng một hạn chế
  2. Điều gì sẽ xảy ra nếu bạn muốn đổi tên một trong các mục nhập client_status? ví dụ. nếu bạn muốn thay đổi tên từ 'affiliate' thành 'affiliate user', bạn sẽ cần cập nhật bảng client mà không cần thiết. Số ID đóng vai trò là tham chiếu và tên là mô tả.

Trong bảng trang web, nếu bạn tự tin rằng tên sẽ là duy nhất thì bạn nên sử dụng làm khóa chính. Cá nhân tôi vẫn sẽ gán một ID số vì nó làm giảm không gian được sử dụng trong các bảng khóa ngoài và tôi thấy dễ quản lý hơn.

EDIT: Như đã nêu ở trên, bạn sẽ gặp sự cố nếu tên trang web được đổi tên. Bằng cách làm cho điều này là chìa khóa chính bạn sẽ làm cho nó rất khó khăn nếu không phải không thể cho điều này được thay đổi vào một ngày sau đó.

+3

Số hai ở trên là lý do tốt nhất để không sử dụng tên làm khóa chính. –

+0

Câu trả lời hay. Đây là một lý do nữa: Hoạt động so sánh chuỗi mất nhiều thời gian hơn sau đó so sánh số. –

+1

Các khóa chính phải KHÔNG BAO GIỜ mang dữ liệu có thể sử dụng được bên ngoài cơ sở dữ liệu.Đó là, lý do duy nhất cho các khóa được sử dụng là để tham khảo các bản ghi trong cơ sở dữ liệu, không phải để trình bày giá trị của các khóa cho người dùng. Lý do cho điều này là các khóa là _immutable_ và dữ liệu thì không. Tên, giới tính, tuổi tác, loại nhân viên, số nhân viên, vv đều có thể thay đổi và không bao giờ được sử dụng làm khóa. Thay vì sử dụng một chuỗi bigint (hoặc bất kỳ thứ tự nào), có một đối số cho việc sử dụng một guid: http://bit.ly/gSIkOG – BryanH

12

Khi thực hiện tự nhiên PRIMARY KEY 's, hãy đảm bảo tính duy nhất của họ nằm dưới sự kiểm soát của bạn.

Nếu bạn hoàn toàn chắc chắn mình sẽ không bao giờ vi phạm tính độc đáo, thì bạn có thể sử dụng các giá trị này làm PRIMARY KEY.

website_statusclient_status dường như được tạo và sử dụng bởi bạn và chỉ bởi bạn, nên chấp nhận sử dụng chúng làm PRIMARY KEY, mặc dù có khóa dài có thể ảnh hưởng đến hiệu suất.

website tên dường như nằm dưới sự kiểm soát của thế giới bên ngoài, đó là lý do tại sao tôi làm cho nó trở thành một lĩnh vực đơn giản. Nếu họ muốn đổi tên website thì sao?

Các mẫu đối sánh sẽ là SSNZIP mã: không phải bạn là người tạo ra chúng và không đảm bảo rằng chúng sẽ không bị lặp lại.

+1

Tôi đã nghe nói về hai người được chỉ định cùng một SSN. Nó không phải là xảy ra, nhưng nó đã xảy ra anyway, trừ khi tôi bị hiểu sai. Một vấn đề lớn hơn là những người sử dụng SSN "giả" để có được việc làm. Bây giờ nguồn dữ liệu của bạn bị hỏng, ngay cả khi Cơ quan quản lý an sinh xã hội đang quản lý SSN chính xác. –

+1

@Walter: điểm của tôi chính xác. SSN KHÔNG nên được sử dụng làm khóa chính – Quassnoi

+1

Tôi thích điểm về sự độc đáo dưới sự kiểm soát của bạn! Chúng tôi thậm chí đã được cho là các lĩnh vực id duy nhất liên tiếp từ khách hàng hóa ra là không duy nhất, khi họ sử dụng lại chúng hoặc đi đến một hệ thống mới. – HLGEM

0

đây vài điểm cần lưu ý trước khi quyết định các phím trong bảng

  • chính Numeric là phù hợp hơn khi bạn tài liệu tham khảo sử dụng (các phím nước ngoài), vì bạn không sử dụng phím nước ngoài, nó ok trong của bạn trường hợp sử dụng khóa không phải số.

  • Phím không phải số sử dụng nhiều không gian hơn phím số, có thể làm giảm hiệu suất .

  • phím Numeric làm db trông đơn giản để hiểu (bạn có thể dễ dàng biết không hàng chỉ bằng cách nhìn vào hàng cuối cùng)
+5

Giá trị của khóa số cho hàng cuối cùng không phải là một dấu hiệu tốt cho tổng số của các hàng trong cơ sở dữ liệu, trừ khi bạn KHÔNG BAO GIỜ xóa một bản ghi trong cơ sở dữ liệu của bạn. –

3

Bên cạnh đó tất cả các điểm tuyệt vời khác đã được thực hiện, tôi sẽ thêm thêm một từ thận trọng khi sử dụng các trường lớn như các khóa phân cụm trong SQL Server (nếu bạn không sử dụng SQL Server, thì điều này có thể không áp dụng cho bạn).

Tôi thêm điều này vì trong SQL Server, khóa chính trên bảng theo mặc định cũng là khóa phân cụm (bạn có thể thay đổi điều đó, nếu bạn muốn và biết về nó, nhưng hầu hết các trường hợp, nó không được thực hiện) .

Phím phân cụm xác định thứ tự vật lý của bảng SQL Server cũng đang được thêm vào mọi chỉ mục không được nhóm trên bảng đó. Nếu bạn chỉ có vài trăm đến vài nghìn hàng và một hoặc hai chỉ số, thì đó không phải là một vấn đề lớn. Nhưng nếu bạn có các bảng lớn thực sự với hàng triệu hàng và có nhiều chỉ mục để tăng tốc các truy vấn, điều này thực sự sẽ gây ra rất nhiều không gian đĩa và bộ nhớ máy chủ bị lãng phí một cách không cần thiết.

Ví dụ: nếu bảng của bạn có 10 triệu hàng, 10 chỉ mục không nhóm và khóa phân cụm của bạn là 26 byte thay vì 4 (cho INT), thì bạn đang lãng phí 10 mio. bởi 10 x 22 byte cho tổng số 2,2 tỷ byte (hoặc 2,2 GByte khoảng) - đó không phải là đậu phộng nữa!

Một lần nữa - điều này chỉ áp dụng cho SQL Server và chỉ khi bạn có các bảng thực sự lớn với nhiều chỉ mục không được nhóm trên chúng.

Marc

+0

"bạn có thể thay đổi, nếu bạn muốn và biết về nó, nhưng hầu hết các trường hợp, nó không được thực hiện" - Chỉ khi người thiết kế cơ sở dữ liệu không phải là một nhà thiết kế cơ sở dữ liệu tốt. Một nhà thiết kế giàu kinh nghiệm và có trình độ sẽ xem xét nhiều thứ trước khi quyết định những gì nên được sử dụng trong chỉ mục nhóm. –

+1

Tom H: vâng, tất nhiên - nhưng đa số các nhà phát triển ứng dụng không cùng lúc với những nhà thiết kế cơ sở dữ liệu tuyệt vời, theo kinh nghiệm cá nhân của riêng tôi. Rất nhiều nhà phát triển ứng dụng coi cơ sở dữ liệu là "kho lưu trữ câm", nơi họ chỉ có thể thả các đối tượng của họ vào - và không nghĩ đủ về thiết kế cơ sở dữ liệu. –

1

Cá nhân, tôi nghĩ bạn sẽ gặp rắc rối khi sử dụng ý tưởng này. Khi bạn kết thúc với nhiều mối quan hệ cha mẹ con, bạn kết thúc với một số lượng lớn công việc khi các tên thay đổi (Vì chúng sẽ luôn luôn sớm hay muộn). Có thể có hiệu suất lớn khi phải cập nhật bảng con có hàng nghìn hàng khi tên của trang web thay đổi. Và bạn phải lập kế hoạch để đảm bảo rằng những thay đổi đó xảy ra. Nếu không, tên trang web thay đổi (oops chúng ta để cho tên hết hạn và người khác mua nó.) Hoặc phá vỡ vì ràng buộc khóa ngoại hoặc bạn cần phải đặt một cách tự động (cập nhật tầng) để truyền bá sự thay đổi thông qua hệ thống. Nếu bạn sử dụng cập nhật xếp tầng, thì bạn có thể đột ngột mang hệ thống của bạn đến một điểm dừng chết trong khi một chage lớn được xử lý. Đây không được coi là một điều tốt. Nó thực sự hiệu quả hơn và hiệu quả để sử dụng id cho các mối quan hệ và sau đó đặt các chỉ mục duy nhất trên trường tên để đảm bảo chúng duy trì. Thiết kế cơ sở dữ liệu cần xem xét việc duy trì tính toàn vẹn dữ liệu và cách thức đó sẽ ảnh hưởng đến hiệu năng.

Một điều nữa cần lưu ý là tên websiten có xu hướng dài hơn một vài ký tự. Điều này có nghĩa sự khác biệt hiệu suất giữa việc sử dụng một trường id cho các phép nối và tên cho các phép nối có thể khá quan trọng.Bạn phải nghĩ về những điều này ở giai đoạn thiết kế vì đã quá muộn để thay đổi thành ID khi bạn có một hệ thống sản xuất với hàng triệu bản ghi đã hết thời gian và sửa chữa là hoàn toàn cơ cấu lại dữ liệu và viết lại tất cả câu lệnh SQL mã. Không phải cái gì bạn có thể sửa chữa trong mười lăm phút để làm cho trang web hoạt động trở lại.

1

Điều này dường như thực sự là một ý tưởng tồi. Nếu bạn cần thay đổi giá trị của enum thì sao? Ý tưởng là làm cho nó thành một cơ sở dữ liệu quan hệ và không phải là một tập hợp các tệp phẳng. Tại thời điểm này, tại sao có bảng client_status? Hơn nữa, nếu bạn đang sử dụng dữ liệu trong một ứng dụng, bằng cách sử dụng một kiểu như GUID hoặc INT, bạn có thể xác nhận loại và tránh dữ liệu xấu (cho đến nay khi xác thực loại). Vì vậy, nó là một trong nhiều dòng để ngăn chặn hack.

8

Kimberly Tripp có một loạt tuyệt vời của bài viết blog (GUIDs as PRIMARY KEYs and/or the clustering keyThe Clustered Index Debate Continues) về vấn đề của việc tạo ra chỉ số nhóm, và chọn khóa chính (các vấn đề liên quan, nhưng không phải lúc nào cũng giống hệt nhau). giới thiệu mình là một chỉ số/khóa chính nhóm nên là:

  1. Unique (nếu không vô dụng như một chìa khóa)
  2. thu hẹp (phím được sử dụng trong tất cả các chỉ số không clustered, và ở nước ngoài mối quan hệ -key)
  3. tĩnh (bạn không muốn phải thay đổi tất cả hồ sơ liên quan)
  4. luôn tăng (hồ sơ nên mới luôn luôn được thêm vào phần cuối của bàn, và không cần phải được chèn vào giữa)

Sử dụng "Tên" làm khóa của bạn, trong khi đó dường như đáp ứng # 1, không đáp ứng BẤT K of ba người còn lại.

Ngay cả đối với "tra cứu" bảng của bạn, những gì nếu sếp của bạn quyết định thay đổi tất cả liên kết s để đối tác s để thay thế? Bạn sẽ phải sửa đổi tất cả các hàng trong cơ sở dữ liệu sử dụng giá trị này.

Từ góc độ hiệu suất, tôi có thể lo ngại nhất là một khóa là hẹp. Nếu tên trang web của bạn thực sự là một URL dài, thì điều đó thực sự có thể làm tăng kích thước của bất kỳ chỉ mục không được nhóm nào và tất cả các bảng sử dụng nó làm khóa ngoại.

1

Tôi cho rằng cơ sở dữ liệu có khả năng chống tham nhũng, ngay cả khi nó chạy chậm hơn một chút, tốt hơn so với một trong đó là ’ t.

Nói chung, các khóa thay thế (chẳng hạn như số nhận dạng tùy ý) làm suy yếu tính toàn vẹn của cơ sở dữ liệu. Các khóa chính là cách chính để xác định các hàng trong cơ sở dữ liệu; nếu các giá trị khóa chính không có ý nghĩa, thì ràng buộc không có ý nghĩa. Do đó, bất kỳ khóa ngoại nào đề cập đến khóa chính thay thế cũng bị nghi ngờ. Bất cứ khi nào bạn phải truy xuất, cập nhật hoặc xóa các hàng riêng lẻ (và được đảm bảo chỉ ảnh hưởng đến một hàng), khóa chính (hoặc một khóa ứng viên khác) là những gì bạn phải sử dụng; phải tìm ra giá trị khóa thay thế là gì khi có một khóa thay thế có ý nghĩa là một bước dư thừa và có khả năng nguy hiểm cho người dùng và ứng dụng.

Thậm chí nếu nó có nghĩa là sử dụng khóa tổng hợp để đảm bảo tính duy nhất, tôi sẽ chủ trương sử dụng một tập hợp thuộc tính tự nhiên, có ý nghĩa làm khóa chính, bất cứ khi nào có thể. Nếu bạn vẫn cần ghi lại các thuộc tính, tại sao lại thêm một thuộc tính khác?Điều đó nói rằng, các khóa thay thế là tốt khi không có khóa tự nhiên, ổn định, chính xác, được bảo đảm là duy nhất (ví dụ: đối với mọi người).

Bạn cũng có thể xem xét sử dụng nén chỉ mục, nếu DBMS của bạn hỗ trợ nó. Điều này có thể rất hiệu quả, đặc biệt là đối với các chỉ mục trên các phím tổng hợp (xem cấu trúc dữ liệu trie) và đặc biệt nếu các thuộc tính ít chọn lọc nhất có thể xuất hiện đầu tiên trong chỉ mục.

2

"Nếu bạn hoàn toàn chắc chắn bạn sẽ không bao giờ có vi phạm duy nhất, thì bạn có thể sử dụng các giá trị này như là PRIMARY KEY's."

Nếu bạn hoàn toàn chắc chắn mình sẽ không bao giờ vi phạm tính độc đáo, thì đừng bận tâm định nghĩa khóa.

1

Tôi nghĩ rằng tôi đồng ý với cheduardo. Đã 25 năm kể từ khi tôi tham gia một khóa học về thiết kế cơ sở dữ liệu nhưng tôi nhớ lại rằng các công cụ cơ sở dữ liệu có thể quản lý và tải các chỉ mục hiệu quả hơn bằng cách sử dụng các phím ký tự. Các ý kiến ​​về cơ sở dữ liệu phải cập nhật hàng ngàn bản ghi khi khóa được thay đổi và trên tất cả các không gian được thêm vào bởi các khóa dài hơn và sau đó phải được chuyển qua các hệ thống, giả định rằng khóa đó thực sự được lưu trữ trong các bản ghi và rằng nó không phải được chuyển qua các hệ thống. Nếu bạn tạo một chỉ mục trên một cột (s) của một bảng, tôi không nghĩ rằng giá trị được lưu trữ trong các bản ghi của bảng (trừ khi bạn thiết lập một số tùy chọn để làm như vậy).

Nếu bạn có một khóa tự nhiên cho một bảng, ngay cả khi nó được thay đổi thường xuyên, việc tạo một khóa khác sẽ tạo ra một dự phòng có thể dẫn đến các vấn đề về tính toàn vẹn dữ liệu và thực sự tạo ra nhiều thông tin hơn cần được lưu trữ và truyền tải trên các hệ thống. Tôi làm việc cho một nhóm đã quyết định lưu trữ các cài đặt ứng dụng cục bộ trong cơ sở dữ liệu. Họ có cột nhận dạng cho mỗi cài đặt, tên phần, tên khóa và giá trị khóa. Họ có một thủ tục lưu trữ (một cuộc chiến thánh) để lưu một thiết lập để đảm bảo nó không xuất hiện hai lần. Tôi vẫn chưa tìm thấy một trường hợp mà tôi sẽ sử dụng ID của thiết lập. Tuy nhiên, tôi đã kết thúc với nhiều bản ghi có cùng phần và tên khóa đã khiến ứng dụng của tôi không thành công. Và có, tôi biết rằng có thể tránh được bằng cách xác định một ràng buộc trên các cột.

+0

Không có lợi ích hiệu quả khi có các phím 'char' trái ngược với các phím số (không phải ở đó, nhất thiết, bất kỳ hình phạt nào). Các giá trị khóa * được * lưu trữ trong 'bản ghi' - tất cả các giá trị là (trừ các cột giá trị lớn, đặc biệt - nhưng bạn sẽ không lập chỉ mục các giá trị đó). Các chỉ mục * trùng lặp * dữ liệu mà chúng đang che phủ. Các trường đó không bao giờ bị xóa khỏi dữ liệu chỉ vì chúng được lập chỉ mục. –

+0

Tôi nghi ngờ liệu dữ liệu được lưu trữ trong bảng hay không là một tùy chọn. "Mức đáy, hoặc lá, của chỉ số nhóm có chứa các hàng dữ liệu thực tế của bảng. Một bảng hoặc khung nhìn được cho phép một chỉ mục nhóm tại một thời điểm." Tôi mơ hồ nhớ lại từ lớp lý thuyết cơ sở dữ liệu của tôi rằng bạn có thể lưu trữ các giá trị cho các cột được lập chỉ mục trong chỉ mục để dữ liệu này không được nhân đôi cho mỗi hàng của bảng. –

Các vấn đề liên quan