med*_*iev 5 mysql sql optimization normalization
我正处于数据库设计的早期阶段,所以还没有最终结果,我正在使用"TOXI"3表设计作为我的线程,它有可选标签,但我不禁觉得加入是不是真的有必要,也许我需要依靠我的posts表中的一个简单的标签列,我可以在其中存储类似的varchar <tag>, <secondTag>.
所以回顾一下:
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;
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
如果有标签:
post_id post_name tags 1 test mma, ufc
将所有标记放在不同的记录中(标准化)意味着您可以在需要时更轻松地重命名标记并跟踪标记名称历史记录.
SO例如,SQL Server至少重命名相关标签三次(mssql- > sqlserver- > sql-server).
将所有标记放在一个记录中(非规范化)意味着您可以使用索引为此列FULLTEXT编制索引,并一次搜索包含两个或多个标记的帖子:
SELECT *
FROM posts
WHERE MATCH(tags) AGAINST('+mma +ufc')
Run Code Online (Sandbox Code Playgroud)
这也是可能的,但标准化设计效率较低.
(不要忘记调整字符的@ft_min_word_len索引标记3或更少以使其工作)
您可以组合两种设计:存储地图表和非规范化列.但这需要更多的维护.
您还可以将规范化设计存储在数据库中,并使用您提供的查询将标记提供给Sphinx或Lucene.
这样,您可以使用MySQL全文标记搜索进行历史挖掘Sphinx,并且不需要额外的维护.