Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 是否真的值得让“价格”正常化;“有毒物质”;路?(3NF)_Sql_Mysql_Optimization_Normalization - Fatal编程技术网

Sql 是否真的值得让“价格”正常化;“有毒物质”;路?(3NF)

Sql 是否真的值得让“价格”正常化;“有毒物质”;路?(3NF),sql,mysql,optimization,normalization,Sql,Mysql,Optimization,Normalization,我正处于数据库设计的早期阶段,所以还没有什么是最终的,我正在为我的线程使用“TOXI”3表设计,其中有可选的标记,但是我忍不住觉得加入并不是真正必要的,也许我需要依赖于我的posts表中的一个简单的tags列,在那里我可以存储一个varchar,比如, 因此,总结一下: 在我的posts表中只添加一个标记列,而在两个标记表上添加额外的左连接是否值得呢 有没有办法优化我的查询 模式 样本数据 当前查询 结果 如果有标签: post_id post_名称标签 1测试mma、ufc 将所有标记放在

我正处于数据库设计的早期阶段,所以还没有什么是最终的,我正在为我的线程使用“TOXI”3表设计,其中有可选的标记,但是我忍不住觉得加入并不是真正必要的,也许我需要依赖于我的
posts
表中的一个简单的tags列,在那里我可以存储一个varchar,比如

因此,总结一下:

  • 在我的
    posts
    表中只添加一个标记列,而在两个标记表上添加额外的左连接是否值得呢
  • 有没有办法优化我的查询
模式 样本数据 当前查询 结果 如果有标签:

post_id post_名称标签 1测试mma、ufc
将所有标记放在不同的记录中(标准化)意味着,如果需要,您可以更轻松地重命名标记并跟踪标记名历史记录

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中有一个标记列表,那么您对标记的查询将非常慢。您将沿着where
post.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')