【问题标题】:Isn't using unnormalized design better when there are multiple JOINS?当有多个 JOINS 时,使用非规范化设计不是更好吗?
【发布时间】:2017-11-12 04:37:03
【问题描述】:

这是我的表结构:

// posts
+----+-----------+---------------------+-------------+
| id |   title   |        body         |   keywords  |
+----+-----------+---------------------+-------------+
| 1  | title1    | Something here      | php,oop     |
| 2  | title2    | Something else      | html,css,js |
+----+-----------+---------------------+-------------+

// tags
+----+----------+
| id |   name   |
+----+----------+
| 1  | php      |
| 2  | oop      |
| 3  | html     |
| 4  | css      |
| 5  | js       |
+----+----------+

// pivot
+---------+--------+
| post_id | tag_id |
+---------+--------+
| 1       | 1      |
| 1       | 2      |
| 2       | 3      |
| 2       | 4      |
| 2       | 5      |
+---------+--------+

如您所见,我以两种方式存储关键字。既作为字符串到名为keywords 的列中,又作为关系到其他表中。


现在我需要选择所有具有特定关键字的帖子(例如phphtml 标签)。我可以通过两种方式做到这一点:

1:使用非规范化设计:

SELECT * FROM posts WHERE keywords REGEXP 'php|html';

2:使用规范化设计:

SELECT     posts.id, posts.title, posts.body, posts.keywords 
FROM       posts
INNER JOIN pivot ON pivot.post_id = posts.id
INNER JOIN tags ON tags.id = pivot.tag_id
WHERE      tags.name IN ('html', 'php')
GROUP BY   posts.id

看到了吗?第二种方法使用两个JOINs。我想它会比在庞大的数据集中使用REGEXP 慢。

你怎么看?我的意思是你的建议是什么,为什么?

【问题讨论】:

  • 一个简单的。不可以。在 MySQL 中,函数不能使用索引。此外,这确实是对 GROUP BY 子句的滥用——尽管令人沮丧的是,它比正确的 DISTINCT 更快
  • 第一个查询可能看起来更快,但实际上它会慢得多,因为使用REGEXP MySQL 必须将keyword 列中的每个值与正则表达式进行比较。 keyword 上的任何索引都将被忽略,整个 posts 表将被扫描。随着posts 表变大,查询会变慢。
  • 你猜。所以呢?我的建议是您阅读有关编程中的抽象和优化的内容,尤其是 SQL/DBMS。 PS你是什么意思,“规范化设计”?这里没有规范化设计,只是在非规范化设计中使用(显式)连接的第二个查询。

标签: mysql sql performance join


【解决方案1】:

第二种方法使用两个 JOIN。我想它会比 在庞大的数据集中使用 REGEXP。

你的直觉完全错了。数据库旨在执行 JOIN。他们可以利用索引和分区来加速查询。更高级的数据库(比 MySQL)使用表的统计信息来选择执行查询的最佳算法。

您的第一个查询始终需要对posts 进行全表扫描。您的第二个查询可以通过多种方式进行优化。

此外,使用第一种方法来保持数据中数据的一致性要困难得多。您可能需要实现触发器来处理所有表的更新和插入。这会减慢速度。

在某些情况下,这样做是值得的 - 考虑一下汇总计数或美元或时间的总数。将标签放入分隔字符串的好处可能要小得多,因为相对于其他成本而言,在 SQL 中解析字符串不太可能带来很大的好处。

【讨论】:

    【解决方案2】:

    在小桌子中,您可以自行决定同时使用两者。

    如果您期望表增长,您确实需要第二选择。背后的原因是 regexp 永远不能在 MySQL 中使用 index。而索引是快速查询的关键。 如果在列上声明了索引,join 将使用索引;

    【讨论】:

      【解决方案3】:

      当我们谈论较小规模的数据时,所有这些看起来都不错。具有非规范化表的 OLTP 系统是非常基本的理论。当您希望您的表可以扩展并希望数据是非冗余和一致的时,规范化就是答案。当然,加入会涉及成本,但这对于所有这些问题来说都是微不足道的。

      让我们谈谈您的场景:

      优点:

      • 查询一张表的所有可用数据。


      缺点:

      • 跨列包装的函数强制查询优化器扫描整个表,而不考虑列索引。从数据扩展的角度来看,这非常重要。
      • 您的案例中的关键字重复了多次领先的数据冗余。
      • 关键字多次出现导致数据不一致,如果要删除/更新关键字,则需要搜索列并替换每一行的所有位置。如果任何情况下关键字遗留在任何地方,都会导致数据完整性问题。

      还有很多。在 RDBMS 中进行数据标准化

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-10
        • 2010-09-16
        • 1970-01-01
        • 2013-01-18
        • 2010-10-07
        • 2010-10-11
        • 2016-05-01
        • 1970-01-01
        相关资源
        最近更新 更多