2009-06-28 41 views
11

Tôi đang thiết kế cơ sở dữ liệu cho một tổ chức có nhiều "loại" người dùng. Lúc đầu, tôi chỉ tạo một bảng người dùng. Tuy nhiên, trong khi tất cả người dùng chia sẻ một số thông tin chung (tên, họ, tên người dùng, mật khẩu, v.v.), mỗi loại người dùng yêu cầu một hoặc hai trường bổ sung không áp dụng cho tất cả người dùng. Trong khi tôi có thể tạo ra các trường bổ sung và đặt chúng là NULL, tôi không muốn làm điều này, vì các trường là khóa ngoài và nó đã gây ra vấn đề cho tôi.Câu hỏi MySQL - Cách xử lý nhiều loại người dùng - một bảng hoặc nhiều người?

Tình huống này thường được xử lý như thế nào?

Cảm ơn!

Trả lời

9

bản năng của bạn để không tạo ra một bảng lớn với rất nhiều NULLS là phải vào. Đó là một ý tưởng tồi, từ một điểm lưu trữ/retrival/bảo trì của xem, cũng như một điểm xác nhận dữ liệu của xem (nhiều hơn về điều đó sau này).

Hai approcaches phổ biến nhất:

1) Có một bảng người dùng với tất cả các trường phổ biến trong nó, trong đó có một trường "loại người dùng". Sau đó, có một bảng riêng biệt cho từng loại người dùng có chứa các trường bổ sung. Tất cả người dùng có một hàng trong bảng người dùng và một hoặc nhiều bảng loại người dùng cụ thể. Đây là chuẩn hóa và lưu trữ nhanh nhất và hiệu quả nhất. Điều này cũng cho phép bạn sử dụng các contraints và các khóa ngoài để đảm bảo rằng tất cả các thông tin cần thiết cho từng loại người dùng có sẵn.

2) Có bảng người dùng với tất cả các trường phổ biến trong đó. Có một bảng khác có tên là UserAttributes có các trường cho userid, key và value. Bất kỳ siêu dữ liệu bổ sung nào cho một người dùng cụ thể đều có thể được lưu trữ tại đây. Điều này có lợi thế là không yêu cầu bất kỳ quản trị cơ sở dữ liệu nào để thêm các loại người dùng hoặc siêu dữ liệu mới được lưu trữ cho từng loại người dùng. Tuy nhiên, nó không cho phép bạn thực hiện bất kỳ xác nhận dữ liệu nào ở cấp DB.

+0

Cảm ơn, dj_segfault. Tôi đã đi với tùy chọn của bạn # 1 và tạo bảng người dùng với các trường chung và trường userType được tham chiếu bởi trường khác, các bảng người dùng "cụ thể" hơn. Các NULLS đã chắc chắn gây đau đầu, tôi vui mừng được loại bỏ chúng ngay bây giờ! – littleK

+0

sửa tôi nếu tôi sai (nó xảy ra rất nhiều) nhưng nếu ai đó lưu trữ dữ liệu của họ theo cách mà các trường phổ biến ở cấp "người dùng" như fname, lname, email, pw ... v.v. . Sẽ không có cách nào để có được thông tin cụ thể hơn của người dùng với một truy vấn đúng không? Nó sẽ luôn luôn mất một truy vấn thứ hai dựa trên usertype để có được bất kỳ thông tin cụ thể hơn. – ackerchez

+0

@ackerchez Chắc chắn là có. Tất cả những gì bạn phải làm để có được TẤT CẢ thông tin là tham gia bên trong tất cả các bảng người dùng kiểu người dùng cụ thể với bảng người dùng chính bởi bất kỳ UID nào của bạn. Các cột cho các bảng không dành cho loại người dùng đó sẽ là rỗng. –

4

Mô hình quan hệ, như vậy, không hỗ trợ "kế thừa", có thể giúp giải quyết vấn đề này (mặc dù một vài động cơ DB, chẳng hạn như PostgreSQL, hỗ trợ kế thừa).

Vì vậy, trước tiên tôi sẽ tự hỏi mình - các loại người dùng khác nhau có cần phải xuất hiện trong cùng một ngữ cảnh không, ít nhất trong một số trường hợp? Nếu vậy, bạn không thể chỉ sao chép và dán "các cột chung" vào nhiều bảng (ít nhất là không làm mất kiểm tra tính toàn vẹn mà bạn có thể nhận được trong các trường hợp đó thông qua các khóa ngoại trên một bảng).

Câu hỏi thứ hai - có phải là bao giờ có thể cho người dùng giữ nhiều hơn một vai trò không? Trong nhiều trường hợp, nó sẽ là khác thường nhưng không hoàn toàn không thể, ví dụ: nhân viên cũng có thể là nhà cung cấp hoặc khách hàng.

Nếu tôi không thể nhận được câu trả lời sắc nét cho những câu hỏi như vậy hướng tôi đi, tôi sẽ thiết lập bảng người dùng chỉ với các trường chung; và các bảng riêng biệt cho các nhà cung cấp, nhân viên, người thử nghiệm beta, khách hàng và bất kỳ loại và vai trò nào khác mà tôi có thể có cho người dùng, mỗi cột chỉ có các cột chuyên biệt của riêng nó cộng với chìa khóa nước ngoài vào bảng người dùng để nhận phần còn lại.

Tôi nhận ra rằng các lược đồ chuẩn hóa đã hết thời trang, nhưng chúng đã phục vụ tôi một cách trung thực trong nhiều thập kỷ và tôi rất yêu thích chúng - tôi chỉ không chuẩn hóa khi tôi cần tối ưu hóa cụ thể. có thể nghĩ!-). Một số phần không chuẩn hóa có thể hữu ích ở đây là một cột liệt kê trong bảng người dùng cho thấy vai trò "chính" hoặc "duy nhất" của mỗi lần sử dụng cụ thể (nó có thể rỗng và có thể đồng đều null khi bắt đầu, nếu tôi đã đủ mạnh để có nó ngay từ đầu ...; -) ... nhưng tôi có thể chờ đợi để thêm nó nếu và khi hiệu suất của một số truy vấn cụ thể cần nó như một tối ưu hóa cụ thể, thay vì thiết kế lược đồ theo cách đó ngay từ đầu (lưu ý rằng đây là lý do chính để không bao giờ sử dụng SELECT * FROM trong các truy vấn của bạn - nếu bạn ALTER TABLE sau đó thêm cột, SELECT * là một bit sẽ bị vỡ! -).

+0

Alex, cảm ơn rất nhiều vì phản hồi của bạn, nó thực sự đã giúp tôi. Tôi đã làm những gì bạn đề nghị, và thiết lập một bảng với các trường chung, cũng như các bảng riêng biệt cho các trường không phổ biến khác cho từng loại người dùng. Tôi cũng đã thêm cột liệt kê vai trò trong bảng người dùng. Cảm ơn! – littleK

1

Đây là câu hỏi bình thường hóa nổi tiếng.

Xem nhanh bài viết này hoặc những người khác thích bài viết đó để tìm câu trả lời phù hợp với nhu cầu kinh doanh.

To normalize or not to normalize

+0

Cảm ơn rất nhiều vì bài viết, thấy nó rất hữu ích. Tôi đã có rất nhiều câu hỏi về chủ đề này, và điều đó đã trả lời rất nhiều câu hỏi. Cảm ơn! – littleK

+0

Sẽ cung cấp +1, nhưng liên kết không hoạt động nữa. Bạn có muốn cập nhật nó không? –

+0

@Gabriel Wow - Tôi không biết liệu nó có hoạt động không. Tôi đã cập nhật nó cho đúng bài viết – Brian

0

Bạn không nói nếu bạn đang sử dụng một ngôn ngữ cấp cao, vì vậy tôi sẽ chỉ đưa ra một ví dụ chung với DB-giống như ví dụ:

Cơ sở dữ liệu thiết kế là khó khăn. Vì vậy, đây sẽ là một câu trả lời nhanh chóng và đơn giản.

Câu hỏi của bạn là câu hỏi cơ bản về mối quan hệ dữ liệu và thiết kế cơ sở dữ liệu. Tìm kiếm một số hướng dẫn cách thực hiện cơ bản để giúp câu trả lời này. Nó có thể giúp suy nghĩ về cách thông tin của bạn được nhóm lại, và liên kết "trở lại" với tập hợp chính (bảng) từ các bộ khác (bảng).

Vì vậy, người dùng là người dùng - đó là bảng của bạn. Nó phải chứa các yếu tố chính (các cột) dữ liệu được liên kết với người dùng.

Sau đó, tập hợp thông tin khác này (ví dụ: quyền hoặc điều gì đó) là một bảng khác.

Chỉ cần đảm bảo rằng bảng khác này có một giá trị (cột) trỏ lại cho người dùng, mà nó đề cập đến. Bạn có thể sẽ muốn nói với cơ sở dữ liệu của bạn để tạo ra một "chỉ số" giữa chúng (để cải thiện màn trình diễn tra cứu, vv)

Ví dụ, A loại "phép" bảng cho người dùng:

- integer "id"  <--- unique, index column, auto-increment 
    - integer "user_id" <--- this is which user this belongs 
    - ... 
    - Boolean "can_write"   <--- example data column 
    - Boolean "can_read"   <--- example data column 
    - Boolean "can_reboot_system" <--- example data column 
    - etc, whatever you want 

Vì vậy, bạn có thể "SELECT * FROM user_table WHERE first_name = 'joe' (hoặc như vậy) ... để có được một người dùng. Trong đó, tôi hy vọng bạn có một số loại 'id' giá trị để xác định hàng đó. Bây giờ, chỉ cần thực hiện quyền 'SELECT * FROM FROM WHERE user_id =' nnnn '(bất kể id của người dùng đó là gì).

Nếu người dùng chỉ có 1 quyền được đặt, thì bạn chỉ có thể có user_id mà không có cột "id" bổ sung.

+0

joej- Tôi chưa bao giờ nghĩ đến việc thể hiện quyền trên cấp cơ sở dữ liệu. Chắc chắn có vẻ như là một ý tưởng hay. Ngay bây giờ, tôi chỉ có một bảng "vai trò" tham chiếu đến một người dùng (và sau đó tôi thực thi vai trò đó bằng mã php). Tôi thích ý tưởng của bạn mặc dù, tôi có kế hoạch để xem xét sử dụng nó nhiều hơn nữa. Cảm ơn! – littleK

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