我正处于数据库设计的早期阶段,所以还没有最终结果,我正在使用“TOXI”3表设计作为我的线程,它有可选的标签,但我不禁感到加入并不是必需的,也许我需要依赖于posts
表中的一个简单的标签列,我可以在其中存储类似<tag>, <secondTag>
的varchar。
所以回顾一下:
posts
表中只有一个标记列。CREATE TABLE `posts` (
`post_id` INT UNSIGNED PRIMARY AUTO_INCREMENT,
`post_name` VARCHAR(255)
) Engine=InnoDB;
CREATE TABLE `post_tags` (
`tag_id` INT UNSIGNED PRIMARY AUTO_INCREMENT,
`tag_name` VARCHAR(255)
) Engine=InnoDB;
CREATE TABLE `post_tags_map` (
`map_id` INT PRIMARY AUTO_INCREMENT,
`post_id` INT NOT NULL,
`tags_id` INT NOT NULL,
FOREIGN KEY `post_id` REFERENCES `posts` (`post_id`),
FOREIGN KEY `post_id` REFERENCES `post_tags` (`tag_id`)
) Engine=InnoDB;
INSERT INTO `posts` (`post_id`, `post_name`)
VALUES
(1, 'test');
INSERT INTO `post_tags` (`tag_id`, `tag_name`)
VALUES
(1, 'mma'),
(2, 'ufc');
INSERT INTO `posts_tags_map` (`map_id`, `post_id`, `tags_id`)
VALUES
(1, 1, 1),
(2, 1, 2);
SELECT
posts.*,
GROUP_CONCAT( post_tags.tag_name order by post_tags.tag_name ) AS tags
FROM posts
LEFT JOIN posts_tags_map
ON posts_tags_map.post_id = posts.post_id
LEFT JOIN post_tags
ON posts_tags_map.tags_id = posts_tags.tag_id
WHERE posts.post_id = 1
GROUP BY post_id
IF 有标签:
post_id post_name tags 1 test mma, ufc
答案 0 :(得分:6)
将所有标记放在不同的记录中(标准化)意味着您可以在需要时更轻松地重命名标记并跟踪标记名称历史记录。
例如, SO
至少重命名SQL Server
个相关标签三次(mssql
- &gt; sqlserver
- &gt; sql-server
)。
将所有标记放在一个记录中(非规范化)意味着您可以使用FULLTEXT
索引为此列编制索引,并一次搜索包含两个或多个标记的帖子:
SELECT *
FROM posts
WHERE MATCH(tags) AGAINST('+mma +ufc')
这也是可能的,但通过标准化设计效率较低。
(不要忘记将@ft_min_word_len
调整为3
字符或更少字符的索引,以使其正常工作)
您可以组合两种设计:存储地图表和非规范化列。但这需要更多的维护。
您还可以将规范化设计存储在数据库中,并使用您提供的查询将代码提供给Sphinx
或Lucene
。
这样,您可以使用MySQL
进行历史记录挖掘,使用Sphinx
进行全文标记搜索,无需额外维护。
答案 1 :(得分:3)
如果你有一个带有标签列表的varchar,那么你对标签的查询会非常慢。你会在post.tag like '%mytag%'
所在的地方做一些事情,这些事情不会在任何地方执行,也不会搜索到索引键。
[编辑] 这项研究显示了performance各种标记系统的方法(包括FULLTEXT索引),并建议你在何时何地使用每一种方法。
答案 2 :(得分:3)
如果使用VARCHAR hack,则几乎不可能查询数据。编写一个查询可以准确有效地显示具有给定标记的所有帖子(并让我们面对它,这是标记系统的一个非常重要的方面)将是完美的:准确性部分很难,因为您需要考虑所有可能性逗号;效率部分很难,因为在字符串中搜索比查看字段的完整值要慢得多(如果可以使用整数,则更慢)。
所以是的,这当然是值得的。
就提高查询速度而言 - 确保在表上有相关索引。对查询运行EXPLAIN以查看放置瓶颈的位置。我不认为在处理每个帖子时获取标签会更好,但它可能是 - 我不确定MySQL在字符串操作方面的效率如何,这就是你在做GROUP_CONCAT时所做的事情。
答案 3 :(得分:2)
加入(当你有正确的索引时)通常比尝试从字段中的逗号分隔字符串中间提取数据要快得多,即使使用全文搜索也是如此。或者您可以使用一堆单独的标记字段(Tag1,tag2,tag3),查询仍然会更难(让我搜索5个字段以查找是否已使用该标记)并且您需要每次添加一个新列您需要添加新标记,并且已经用完了现有列。规范化的数据库设计是最好的,最高效的方式。数据库旨在使用连接。为什么你不想使用它们超出我的范围。