2009-03-19 32 views
6

EDIT: Để mọi người xây dựng hệ thống gắn thẻ. Đừng đọc điều này. Nó không phải là những gì bạn đang tìm kiếm. Tôi hỏi điều này khi tôi không nhận thức được rằng RDBMS đều có phương pháp tối ưu hóa riêng của họ, chỉ cần sử dụng một sơ đồ đơn giản đến nhiều.Sơ đồ gắn thẻ cơ sở dữ liệu có thể mở rộng

Tôi có hệ thống đăng bài có hàng triệu bài đăng. Mỗi bài đăng có thể có số lượng thẻ vô hạn được liên kết với nó.

Người dùng có thể tạo thẻ có ghi chú, ngày tạo, chủ sở hữu, v.v. Một thẻ gần giống như bài đăng, bởi vì mọi người có thể đăng ghi chú về thẻ.

Mỗi liên kết thẻ có chủ sở hữu và ngày, vì vậy chúng tôi có thể xem ai đã thêm thẻ và thời điểm.

Câu hỏi của tôi là làm cách nào để tôi có thể triển khai tính năng này? Nó phải nhanh chóng tìm kiếm các bài viết theo tag, hoặc các thẻ của bài viết. Ngoài ra, người dùng có thể thêm thẻ vào bài đăng bằng cách nhập tên vào trường, giống như thanh tìm kiếm của Google, nó phải điền vào phần còn lại của tên thẻ cho bạn.

Tôi có 3 giải pháp vào lúc này nhưng không chắc chắn giải pháp nào là tốt nhất hoặc nếu có cách nào tốt hơn.

Lưu ý rằng tôi không hiển thị bố cục ghi chú vì nó sẽ không đáng kể khi tôi nhận được giải pháp thích hợp cho thẻ.

Phương pháp 1. danh sách liên kết

tagId trong bài điểm vào một danh sách liên kết trong tag_assoc, ứng dụng phải đi qua danh sách cho đến khi flink = 0

post:   id, content, ownerId, date, tagId, notesId 
tag_assoc:  id, tagId, ownerId, flink 
tag:   id, name, notesId 

Phương pháp 2. denormalization

thẻ chỉ đơn giản là một trường VARCHAR hoặc TEXT có chứa một mảng được phân cách bằng thẻ tagId: ownerId. Nó không thể là một kích thước cố định.

post:   id, content, ownerId, date, tags, notesId 
tag:   id, name, notesId 

Phương pháp 3. Toxi

(từ: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html, cũng điều tương tự ở đây: Recommended SQL database design for tags or tagging)

post:   id, content, ownerId, date, notesId 
tag_assoc:  ownerId, tagId, postId 
tag:   id, name, notesId 

Phương pháp 3 đặt ra câu hỏi, làm thế nào nhanh chóng sẽ nó được lặp đi lặp lại qua từng một hàng trong tag_assoc?

Phương pháp 1 và 2 phải nhanh để trả lại thẻ theo bài đăng, nhưng đối với bài đăng theo thẻ, phải tìm một bảng tra cứu khác.

Điều cuối cùng tôi phải lo lắng là tối ưu hóa tìm kiếm thẻ theo tên, tôi chưa làm việc đó.

tôi đã thực hiện một sơ đồ ASCII ở đây: http://pastebin.com/f1c4e0e53

Trả lời

0

Bill Tôi nghĩ rằng tôi đã loại bỏ bạn ra, các ghi chú chỉ là trong một bảng khác và có một bảng riêng biệt với các ghi chú được đăng bởi những người khác nhau. Bài đăng có ghi chú và thẻ, nhưng thẻ cũng có ghi chú, đó là lý do tại sao thẻ là UNIQUE.

Jonathan đúng về danh sách được liên kết, tôi hoàn toàn không sử dụng chúng. Tôi quyết định để thực hiện các thẻ theo cách bình thường đơn giản nhất mà các loại thịt nhu cầu của tôi:

DROP TABLE IF EXISTS `tags`; 
CREATE TABLE IF NOT EXISTS `tags` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `owner` int(10) unsigned NOT NULL, 
    `date` int(10) unsigned NOT NULL, 
    `name` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `name` (`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

DROP TABLE IF EXISTS `posts`; 
CREATE TABLE IF NOT EXISTS `posts` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `owner` int(10) unsigned NOT NULL, 
    `date` int(10) unsigned NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `content` TEXT NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

DROP TABLE IF EXISTS `posts_notes`; 
CREATE TABLE IF NOT EXISTS `posts_notes` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `owner` int(10) unsigned NOT NULL, 
    `date` int(10) unsigned NOT NULL, 
    `postId` int(10) unsigned NOT NULL, 
    `note` TEXT NOT NULL, 
    PRIMARY KEY (`id`), 
    FOREIGN KEY (`postId`) REFERENCES posts(`id`) ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

DROP TABLE IF EXISTS `posts_tags`; 
CREATE TABLE IF NOT EXISTS `posts_tags` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `owner` int(10) unsigned NOT NULL, 
    `tagId` int(10) unsigned NOT NULL, 
    `postId` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`id`), 
    FOREIGN KEY (`postId`) REFERENCES posts(`id`) ON DELETE CASCADE, 
    FOREIGN KEY (`tagId`) REFERENCES tags(`id`) ON DELETE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; 

Tôi không chắc chắn nhanh như thế nào đây sẽ là trong tương lai, nhưng nó phải là tốt cho một thời gian như chỉ có một vài người sử dụng cơ sở dữ liệu.

0

"Thẻ là gần giống như một bài riêng của mình, bởi vì mọi người có thể đăng ghi chú về thẻ." - cụm từ này làm cho tôi nghĩ rằng bạn thực sự chỉ muốn một bảng cho POST, với khóa chính và khóa ngoài tham chiếu đến bảng POST. Bây giờ bạn có thể có bao nhiêu thẻ cho mỗi bài đăng vì không gian đĩa của bạn sẽ cho phép.

Tôi giả định không có nhu cầu cho nhiều đối với nhiều giữa POST và thẻ, vì thẻ không được chia sẻ qua bài viết, dựa trên này:

"Người dùng có thể tạo ra các thẻ có ghi chú, ngày tạo, chủ sở hữu, v.v. "

Nếu ngày tạo và chủ sở hữu được chia sẻ, đó sẽ là hai mối quan hệ khóa ngoài bổ sung, IMO.

+0

Thẻ được chia sẻ trên các bài đăng. Tôi đã quyết định khá nhiều về phương pháp 3 ngay bây giờ. Mỗi bảng có thể có thẻ sẽ có một bảng khác gọi là _tags. EG: news_tags. Tôi vẫn còn sơ sài về phương pháp này, nhưng mọi người dường như đề xuất nó, vì vậy tôi giả sử MySQL sẽ tối ưu hóa nó. –

+0

"giả định" - ý tưởng tồi. Biết là tốt hơn. – duffymo

2

Sau đây là cách tôi muốn làm điều đó:

posts:   [postId], content, ownerId, date, noteId, noteType='post' 
tag_assoc:  [postId, tagName], ownerId, date, noteId, noteType='tagAssoc' 
tags:   [tagName], ownerId, date, noteId, noteType='tag' 
notes:   [noteId, noteType], ownerId, date, content 

Các lĩnh vực trong ngoặc vuông là khóa chính của bảng tương ứng.

Xác định ràng buộc trên noteType trong mỗi bảng: posts, tag_assoctags. Điều này ngăn không cho một lưu ý nhất định áp dụng cho cả hai ví dụ posttag.

Đặt tên thẻ làm chuỗi ngắn, không phải là số nguyên id. Bằng cách đó, bạn có thể sử dụng chỉ số bao gồm [postId, tagName] trong bảng tag_assoc.

Thực hiện hoàn tất thẻ bằng lệnh gọi AJAX. Nếu người dùng nhập "datab" cho một thẻ, trang web của bạn thực hiện cuộc gọi AJAX và ở phía máy chủ, truy vấn ứng dụng: SELECT tagName FROM tags WHERE tagName LIKE ?||'%'.

0

Danh sách được liên kết gần như chắc chắn là cách tiếp cận sai. Nó chắc chắn có nghĩa là các truy vấn của bạn sẽ phức tạp hoặc phụ tối ưu - rất mỉa mai vì lý do có khả năng nhất để sử dụng danh sách được liên kết là giữ dữ liệu theo thứ tự được sắp xếp chính xác. Tuy nhiên, tôi không thấy một cách dễ dàng để tránh tìm nạp lại một hàng lặp đi lặp lại, và sau đó sử dụng giá trị nháy được truy lục đến điều kiện hoạt động chọn cho hàng tiếp theo.

Vì vậy, hãy sử dụng phương pháp tiếp cận dựa trên bảng với khóa ngoài thông thường cho các tham chiếu khóa chính. Cái được vạch ra bởi Bill Karwin trông giống như những gì tôi phác thảo.

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