Thực hiện Nhận xét và Lượt thích trong cơ sở dữ liệu


145

Tôi là một nhà phát triển phần mềm. Tôi thích viết mã, nhưng tôi ghét cơ sở dữ liệu ... Hiện tại, tôi đang tạo một trang web mà người dùng sẽ được phép đánh dấu một thực thể là thích (như trong FB), gắn thẻnhận xét .

Tôi bị kẹt trên thiết kế bảng cơ sở dữ liệu để xử lý chức năng này. Giải pháp là tầm thường, nếu chúng ta chỉ có thể làm điều này cho một loại điều (ví dụ: ảnh). Nhưng tôi cần kích hoạt điều này cho 5 thứ khác nhau (hiện tại, nhưng tôi cũng cho rằng con số này có thể tăng lên, khi toàn bộ dịch vụ tăng lên).

Tôi đã tìm thấy một số câu hỏi tương tự ở đây, nhưng không ai trong số họ có câu trả lời thỏa mãn, vì vậy tôi lại hỏi câu hỏi này.

Câu hỏi là, làm thế nào để thiết kế cơ sở dữ liệu đúng cách, hiệu quảlinh hoạt, để nó có thể lưu trữ các bình luận cho các bảng khác nhau , thích cho các bảngthẻ khác nhau cho chúng. Một số mẫu thiết kế như câu trả lời sẽ là tốt nhất;)

Mô tả chi tiết : Tôi có một bảng User với một số dữ liệu người dùng và 3 bảng nữa : Photovới các bức ảnh , Articlesvới các bài báo , Placesvới các địa điểm . Tôi muốn cho phép bất kỳ người dùng nào đăng nhập để:

  • nhận xét về bất kỳ 3 bảng nào

  • đánh dấu bất kỳ ai trong số họ là thích

  • gắn thẻ bất kỳ trong số họ với một số thẻ

  • Tôi cũng muốn đếm số lượt thích cho mỗi yếu tố và số lần thẻ cụ thể được sử dụng.

Cách tiếp cận thứ 1 :

a) Đối với thẻ , tôi sẽ tạo ra một bảng Tag [TagId, tagName, tagCounter] , sau đó tôi sẽ tạo ra nhiều-nhiều mối quan hệ bảng cho: Photo_has_tags, Place_has_tag, Article_has_tag.

b) Cùng tính cho ý kiến.

c) Tôi sẽ tạo ra một bảng LikedPhotos [idUser, idPhoto] , LikedArticles[idUser, idArticle], LikedPlace [idUser, idPlace]. Số lượt thích sẽ được tính bằng các truy vấn (trong đó, tôi cho là xấu). Và ...

Tôi thực sự không thích thiết kế này cho phần cuối cùng, nó có mùi rất tệ đối với tôi;)


2 nd cách tiếp cận :

Tôi sẽ tạo một bảng ElementType [idType, TypeName == some table name]sẽ được quản trị viên (tôi) điền vào với tên của các bảng có thể được thích , nhận xét hoặc được gắn thẻ . Sau đó, tôi sẽ tạo các bảng :

a) LikedElement [idLike, idUser, idElementType, idLikedElement]và tương tự cho Nhận xét và Thẻ với các cột thích hợp cho mỗi cột. Bây giờ, khi tôi muốn làm cho một bức ảnh thích, tôi sẽ chèn:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Photo'
INSERT (user id, typeId, photoId)

và cho các địa điểm:

typeId = SELECT id FROM ElementType WHERE TypeName == 'Place'
INSERT (user id, typeId, placeId)

và v.v. ... Tôi nghĩ rằng cách tiếp cận thứ hai tốt hơn, nhưng tôi cũng cảm thấy như thiếu một cái gì đó trong thiết kế này ...

Cuối cùng, tôi cũng tự hỏi nơi tốt nhất để lưu trữ bộ đếm cho bao nhiêu lần yếu tố được thích là. Tôi chỉ có thể nghĩ về hai cách:

  1. trong Photo/Article/Placebảng phần tử ( )
  2. bằng cách chọn đếm ().

Tôi hy vọng rằng lời giải thích của tôi về vấn đề này kỹ lưỡng hơn bây giờ.


Bạn đã xem xét XML chưa?
CodyBugstein

1
Tôi hiếm khi tìm thấy những câu hỏi như thế này là 100% những gì tôi có trong đầu, câu hỏi của bạn hoàn toàn tuyệt vời! Cảm ơn @Kokos.
aderchox

Câu trả lời:


194

Giải pháp mở rộng nhất là chỉ có một bảng "cơ sở" (được kết nối với "thích", thẻ và nhận xét) và "kế thừa" tất cả các bảng khác từ đó. Thêm một loại thực thể mới liên quan đến việc chỉ cần thêm một bảng "kế thừa" mới - sau đó nó sẽ tự động cắm vào toàn bộ máy thích / tag / bình luận.

Thuật ngữ mối quan hệ thực thể cho điều này là "thể loại" (xem Hướng dẫn phương pháp ERwin , phần: "Mối quan hệ phụ"). Biểu tượng thể loại là:

thể loại

Giả sử người dùng có thể thích nhiều thực thể, một thẻ có thể được sử dụng cho nhiều hơn một thực thể nhưng một nhận xét là dành riêng cho thực thể, mô hình của bạn có thể trông như thế này:

Sơ đồ ER


BTW, có khoảng 3 cách để thực hiện "danh mục ER":

  • Tất cả các loại trong một bảng.
  • Tất cả các loại bê tông trong các bảng riêng biệt.
  • Tất cả các loại cụ thể và trừu tượng trong các bảng riêng biệt.

Trừ khi bạn có các yêu cầu hiệu suất rất nghiêm ngặt, cách tiếp cận thứ ba có lẽ là tốt nhất (có nghĩa là các bảng vật lý khớp với 1: 1 các thực thể trong sơ đồ trên).


2
câu trả lời tuyệt vời, cảm ơn bạn. Tôi hy vọng, tôi sẽ quản lý để thực hiện nó ... và tôi tự hỏi Django ORM sẽ xử lý như thế nào để lập bản đồ đó (hoặc tôi sẽ tự làm điều đó như thế nào ... nhưng, đó là vấn đề khác;)) Nhưng, bạn có thể giải thích tôi, bởi vì tôi nghĩ rằng tôi không hiểu đúng về nó - những gì bạn đã rút ra cho tôi (cảm ơn!) là cách tiếp cận thứ ba mà bạn đề cập?
Kokos

2
@Kokos Về cơ bản, cách tiếp cận (3) có nghĩa là ENTITY là một bảng, PHOTO là một bảng, NGHỆ THUẬT là một bảng và PLACE là một bảng. Cách tiếp cận (2) có nghĩa là không có bảng cho ENTITY và cách tiếp cận (1) có nghĩa là chỉ có một bảng. Sự tồn tại của tất cả các cách tiếp cận này (tất cả đều có điểm mạnh và điểm yếu) là hậu quả đáng tiếc của thực tế là một RDBMS điển hình không hỗ trợ kế thừa bảng nguyên bản.
Branko Dimitrijevic

1
+1 cảm ơn vì lời giải thích tuyệt vời và tài liệu tham khảo về "danh mục". Tôi sẽ gửi một câu hỏi gần với điều này nhưng bạn đã trả lời nó ở đây.
andy holaday

2
@BrankoDimitrijevic Tại sao các bảng thực thể Ảnh, Bài viết, Địa điểm không có PK riêng, ví dụ PhotoID, ArticleID, v.v. nhưng cũng có một cột khác cho Entity_ID là FK? Điều này có cần thiết không?
tập một

3
@Orion Tối đa cho BIGINTlà 9223372036854775807. Giả sử bạn chèn một hàng mỗi giây, bạn sẽ hết các giá trị khả dụng trong ~ 300 tỷ năm. Chắc chắn, bạn sẽ có thể chuyển sang số nguyên 128 bit sau đó!
Branko Dimitrijevic

22

Vì bạn "ghét" cơ sở dữ liệu, tại sao bạn lại cố gắng thực hiện một cơ sở dữ liệu? Thay vào đó, tìm kiếm sự giúp đỡ từ một người yêu thích và hít thở thứ này.

Nếu không, học cách yêu cơ sở dữ liệu của bạn. Một cơ sở dữ liệu được thiết kế tốt giúp đơn giản hóa việc lập trình, thiết kế trang web và làm trơn tru hoạt động liên tục của nó. Ngay cả một nhà thiết kế d / b có kinh nghiệm cũng sẽ không có tầm nhìn xa hoàn hảo và hoàn hảo: một số thay đổi lược đồ sẽ cần thiết khi mô hình sử dụng xuất hiện hoặc yêu cầu thay đổi.

Nếu đây là một dự án một người, hãy lập trình giao diện cơ sở dữ liệu thành các hoạt động đơn giản bằng cách sử dụng các thủ tục được lưu trữ: add_user, update_user, add_comment, add_like, upload_photo, list_comments, v.v. Không nhúng lược đồ vào một dòng mã. Theo cách này, lược đồ cơ sở dữ liệu có thể được thay đổi mà không ảnh hưởng đến bất kỳ mã nào: chỉ các thủ tục được lưu trữ mới biết về lược đồ.

Bạn có thể phải cấu trúc lại lược đồ nhiều lần. Điều này là bình thường. Đừng lo lắng về việc làm cho nó hoàn hảo ngay lần đầu tiên. Chỉ cần làm cho nó đủ chức năng để tạo mẫu cho một thiết kế ban đầu. Nếu bạn có thời gian xa xỉ, hãy sử dụng nó một chút, sau đó xóa lược đồ và thực hiện lại. Nó luôn luôn tốt hơn lần thứ hai.


2
Bởi vì tôi cần phải tự thực hiện nó. Ít nhất là bây giờ ... và, tôi nghĩ rằng có lẽ đó là một dịp tốt để bắt đầu thích một cơ sở dữ liệu một chút;) Cảm ơn bạn về đề xuất của bạn với thủ tục được lưu trữ. Có ai biết, nếu chúng được ánh xạ bởi Django ORM tự động?
Kokos

6
Tôi yêu câu cuối cùng của bạn - Nó luôn luôn tốt hơn lần thứ hai.
Lewis

2
Nó luôn luôn tốt hơn lần thứ hai. Yup
Gammer

20

Đây là một ý tưởng chung, xin vui lòng không chú ý đến kiểu dáng tên trường, nhưng nhiều hơn về mối quan hệ và cấu trúc

nhập mô tả hình ảnh ở đây

Mã giả này sẽ nhận được tất cả các nhận xét về ảnh với ID 5
CHỌN * TỪ các hành động
WHERE hành động.id_Stuff = 5
VÀ hành động.typeStuff = "ảnh"
AND Action.typeAction = "bình luận"

Mã giả này sẽ nhận được tất cả lượt thích hoặc người dùng thích ảnh có ID 5
(bạn có thể sử dụng số đếm () để chỉ nhận được số lượt thích)

SELECT * FROM actions  
WHERE actions.id_Stuff = 5  
AND actions.typeStuff="photo"  
AND actions.typeAction = "like"  

Tôi nghĩ bạn thậm chí có thể thích bình luận, như, nhấp vào liên kết "thích" trong một bình luận. Truy vấn này sẽ nhận được lượt thích bình luận (hành động) với ID 133: SELECT * FROM actions WHERE actions.id=133 AND actions.typeStuff = "comment" AND actions.typeAction = "like"
user964260

1
Tôi chắc chắn sẽ nhớ giải pháp này để phát hành thêm hệ thống của mình :)
Kokos

Tôi có 2 bảng Stuff Stuff1 và Stuff2 ... Tôi đã theo sơ đồ này nhưng có lỗi sql trong khi sử dụng ... Stuff1, Stuff2 là hai bảng độc lập với các khóa chính độc lập của chúng và bảng hành động có một cột id_ ware đang tham chiếu đến hai tabel Stuff1, Stuff2. Bây giờ, ví dụ Stuff1 có 5 hàng, Stuff2 có 10 hàng, khi tôi cố gắng thêm hàng trong bảng hành động với id_ ware bất cứ điều gì nhỏ hơn 5 cho phép '3' nó thực hiện truy vấn vì tồn tại một hàng có id_ ware '3' trong cả Stuff1 và Stuff2, nhưng nếu tôi cố gắng thêm hàng với id_ ware lớn hơn 5 ... (tiếp tục nhận xét tiếp theo)
vikas devde

1
Nếu ai đó thực hiện lượt thích theo cách này, nó sẽ khiến việc thông báo cho người dùng lượt thích mới trở nên khó khăn hơn. Nó sẽ yêu cầu một bảng khác.
Greg L

4
Làm thế nào id_stuffcột sẽ chứa các giá trị duy nhất trong mỗi ba bảng?
tập một

0

trong khả năng hiểu biết của tôi. một số bảng được yêu cầu. Có rất nhiều mối quan hệ giữa chúng.

  • Bảng lưu trữ dữ liệu người dùng như tên, họ, ngày sinh với trường nhận dạng.
  • Bảng lưu trữ các loại dữ liệu. Những loại này có thể là hình ảnh, chia sẻ, liên kết. mỗi loại phải có một bảng duy nhất. do đó, có một mối quan hệ giữa các bảng riêng lẻ của chúng và bảng này.
  • mỗi loại dữ liệu khác nhau có bảng của nó. ví dụ, cập nhật trạng thái, hình ảnh, liên kết.
  • bảng cuối cùng dành cho nhiều người có nhiều quan hệ lưu trữ id, id người dùng, loại dữ liệu và id dữ liệu.

nếu bạn đăng sơ đồ cơ sở dữ liệu của bạn. tôi có thể vẽ mối quan hệ.
erencan

0

Nhìn vào các mẫu truy cập bạn sẽ cần. Có ai trong số họ dường như làm cho đặc biệt khó khăn hoặc không hiệu quả một lựa chọn thiết kế của tôi hay khác?

Nếu không ủng hộ cái cần ít bảng hơn

Trong trường hợp này:

  1. Thêm nhận xét: bạn có thể chọn nhiều / nhiều bảng cụ thể hoặc chèn vào một bảng chung với một mã định danh cụ thể đã biết cho những gì đang được thích, tôi nghĩ mã khách hàng sẽ đơn giản hơn một chút trong trường hợp thứ hai của bạn.
  2. Tìm nhận xét cho mục: ở đây có vẻ như sử dụng bảng chung dễ hơn một chút - chúng tôi chỉ có một truy vấn duy nhất được tham số hóa theo loại thực thể
  3. Tìm bình luận của một người về một loại điều: truy vấn đơn giản trong cả hai trường hợp
  4. Tìm tất cả các ý kiến ​​của một người về tất cả mọi thứ: điều này có vẻ hơi sởn gai ốc.

Tôi nghĩ rằng cách tiếp cận "phân biệt đối xử" của bạn, tùy chọn 2, mang lại các truy vấn đơn giản hơn trong một số trường hợp và dường như không tệ hơn trong các cách khác vì vậy tôi sẽ thực hiện theo.


0

Chắc chắn đi với cách tiếp cận thứ hai trong đó bạn có một bảng và lưu trữ loại phần tử cho mỗi hàng, nó sẽ giúp bạn linh hoạt hơn rất nhiều. Về cơ bản khi một cái gì đó có thể được thực hiện một cách hợp lý với ít bảng hơn thì hầu như luôn luôn tốt hơn với ít bảng hơn. Một ưu điểm xuất hiện trong đầu tôi về trường hợp cụ thể của bạn, xem xét bạn muốn xóa tất cả các yếu tố thích của một người dùng nào đó, với cách tiếp cận đầu tiên của bạn, bạn cần đưa ra một truy vấn cho từng loại yếu tố nhưng với cách tiếp cận thứ hai thì có thể thực hiện được chỉ với một truy vấn hoặc xem xét khi bạn muốn thêm một loại phần tử mới, với cách tiếp cận đầu tiên, nó liên quan đến việc tạo một bảng mới cho mỗi loại mới nhưng với cách tiếp cận thứ hai, bạn không nên làm gì cả ...


-1

Xem xét sử dụng bảng cho mỗi thực thể để nhận xét và vv Bảng khác - phân chia và chia tỷ lệ tốt hơn. Không phải là vấn đề để kiểm soát nhiều bảng tương tự cho tất cả các khung mà tôi biết.

Một ngày nào đó bạn sẽ cần tối ưu hóa việc đọc từ cấu trúc như vậy. Bạn có thể dễ dàng tạo các bảng khó chịu trên các bảng cơ sở và mất một chút khi viết.

Một bảng lớn với từ điển có thể trở nên không thể kiểm soát một ngày nào đó.


Nhiều bảng hơn có nghĩa là nó sẽ ít được bảo trì hơn. Các bảng riêng lẻ có thể được loại bỏ bởi hầu hết các d / bs.
wallyk
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.