Sql 是否真的值得让“价格”正常化;“有毒物质”;路?(3NF)
我正处于数据库设计的早期阶段,所以还没有什么是最终的,我正在为我的线程使用“TOXI”3表设计,其中有可选的标记,但是我忍不住觉得加入并不是真正必要的,也许我需要依赖于我的Sql 是否真的值得让“价格”正常化;“有毒物质”;路?(3NF),sql,mysql,optimization,normalization,Sql,Mysql,Optimization,Normalization,我正处于数据库设计的早期阶段,所以还没有什么是最终的,我正在为我的线程使用“TOXI”3表设计,其中有可选的标记,但是我忍不住觉得加入并不是真正必要的,也许我需要依赖于我的posts表中的一个简单的tags列,在那里我可以存储一个varchar,比如, 因此,总结一下: 在我的posts表中只添加一个标记列,而在两个标记表上添加额外的左连接是否值得呢 有没有办法优化我的查询 模式 样本数据 当前查询 结果 如果有标签: post_id post_名称标签 1测试mma、ufc 将所有标记放在
posts
表中的一个简单的tags列,在那里我可以存储一个varchar,比如,
因此,总结一下:
- 在我的
表中只添加一个标记列,而在两个标记表上添加额外的左连接是否值得呢posts
- 有没有办法优化我的查询
将所有标记放在不同的记录中(标准化)意味着,如果需要,您可以更轻松地重命名标记并跟踪标记名历史记录
SO
,例如,至少三次重命名了SQL Server
相关标记(mssql
->SQL Server
->SQL Server
)
将所有标签放在一条记录中(非规范化)意味着您可以使用FULLTEXT
索引索引此列,并同时搜索具有两个或多个标签的帖子:
SELECT *
FROM posts
WHERE MATCH(tags) AGAINST('+mma +ufc')
这也是可能的,但标准化设计的效率较低
(不要忘记调整@ft\u min\u word\u len
以索引3个或更少字符的标签,以使其正常工作)
您可以组合这两种设计:同时存储映射表和非规范化列。不过,这需要更多的维护
您还可以将规范化设计存储在数据库中,并使用提供的查询将标记提供给Sphinx
或Lucene
通过这种方式,您可以使用MySQL
进行历史挖掘,使用Sphinx
进行全文标记搜索,并且无需额外维护。如果您的varchar中有一个标记列表,那么您对标记的查询将非常慢。您将沿着wherepost.tag这样的行执行一些操作,比如“%mytag%”
,这与搜索索引键一样,在任何地方都不会执行
[编辑]
这项研究展示了使用标签系统的各种方法(包括全文索引),并建议您在何时何地使用每种方法。如果使用VARCHAR hack,您几乎不可能查询数据。这将是地狱,写一个查询,准确和有效地显示所有职位与一个给定的标签(让我们面对它,这是一个相当大的方面的标签系统):准确性部分是困难的,因为你需要考虑所有可能性的逗号;效率部分很难,因为在字符串中搜索要比查看字段的完整值慢得多(如果可以使用整数,则更慢)
所以,是的,这绝对是值得的
为了加快查询速度,请确保表上有相关的索引。对查询运行解释以查看瓶颈的位置。我不认为在处理每一篇文章时为其获取标签会更好,但可能会更好——我不确定MySQL在字符串操作方面的效率,这是在您进行组连接时它所做的。加入(当您有正确的索引时)通常比尝试从字段中逗号分隔字符串的中间提取数据要快得多,即使使用全文搜索也是如此。或者您可以使用一组单独的标记字段(Tag1、tag2、tag3),查询将更加困难(让我搜索5个字段以查找我是否使用了该标记),并且每次需要添加新标记并且已经使用完现有列时,您都需要添加一个新列。规范化数据库设计是最好的、性能最好的方法。数据库设计为使用联接。我无法理解你为什么不想使用它们。为什么地图id
?这对(post\u id,tags\u id)
是唯一的。@jensgram:有些人更喜欢代理键,甚至在多对多表上也是如此。而且一些ORM不支持复合PK…请注意,如果使用默认设置,全文索引不会索引这两个单词:它至少需要4个字符。您可以更改设置,但需要进行更改。全文索引是专为此类查询而设计的。它会像在索引列上查询id一样快吗?@Jeremy French
:哪一列?您不能创建普通索引来索引一条带有两个键的记录。当然,检索包含一系列id的所有帖子的查询是可能的,但效率较低。在上面的模式中,查询post_标记的名称需要一次文本查找,其中全文索引将帮助您。然后在post_标记上加入一个可以使用数字索引的映射。OP中的另一种方法是使用一个非规范化字符串,其中包含以逗号分隔的标记列表。这将比标准化版本慢。@Jeremy French
:全文
索引专为快速查询逗号分隔(或任何分隔)字符串而设计。如果字段中有不同的单词,它会用相同数量的键索引一个记录。比如说,您需要查询所有标记为sql
、mysql
、优化
和规范化
(一次完成)的帖子。使用全文
索引:匹配('+sql+mysql+optimization+normalization')
非常简单高效。现在,您将如何对规范化模式执行相同的操作?
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
post_id post_name tags
1 test mma, ufc
SELECT *
FROM posts
WHERE MATCH(tags) AGAINST('+mma +ufc')