【问题标题】:How costly are JOINs in SQL? And/or, what's the trade off between performance and normalization?SQL 中的 JOIN 成本有多高?和/或,性能和标准化之间的权衡是什么?
【发布时间】:2011-08-12 00:43:44
【问题描述】:

我找到了一个类似的主题,但它并没有真正抓住我想要问的本质 - 所以我创建了一个新主题。

我知道规范化和性能之间存在权衡,我想知道绘制这条线的最佳做法是什么?在我的特定情况下,我的消息传递系统具有三个不同的表:messages_threads(总体消息持有者)、messages_recipients(参与人员)和messages_messages(实际消息+时间戳)。

为了返回“收件箱”视图,我必须将messages_threads 表、users 表和pictures 表左连接到messages_recipients 表,以获取填充视图的信息(个人资料图片、发件人姓名、线程id)...我仍然需要添加一个消息连接以从最后一条消息中检索文本,以便向用户显示最后一条消息的“预览”。

我的问题是:SQL 中的 JOINS 对性能的影响有多大?例如,我可以在 messages_threads 表中名为“sendername”的字段下存储发件人的姓名(我必须让用户加入才能检索) - 但就规范化而言,我一直被教导要避免数据冗余?

你在哪里画线?还是我高估了 SQL 连接对性能的影响?

【问题讨论】:

    标签: mysql sql performance join


    【解决方案1】:

    最佳做法是始终从 3NF 开始,然后仅在发现特定性能问题时才考虑非规范化。

    性能只是您必须处理的数据库问题中的一个。通过复制数据,您冒着允许不一致的数据存在于数据库中的风险,从而使关系数据库的核心原则之一无效(一致性(ACID 中的Ca

    是的,加入是有代价的,这是无法避免的。但是,成本通常比您想象的要低很多,并且经常会被网络传输时间等其他因素所淹没。通过确保相关列被正确编入索引,您可以避免很多这样的成本。

    并且,请记住优化口号:衡量,不要猜测!并在类似生产的环境中进行衡量。并且保持定期测量(和调整) - 如果您的架构和数据永远不会改变(不太可能),优化只是一种设置和忘记操作。


    a) 通过使用触发器来保持一致性,通常可以安全地恢复性能。当然,这会减慢您的更新速度,但仍可能让您的选择运行得更快。

    【讨论】:

    • 谢谢你,你说得对——我应该坚持 ACID。感谢您澄清这一点,我阅读了一篇关于大型网站非规范化的文章并开始质疑我的结构。
    • @Walker,非规范化有时是一个可行的选择。您只需要确保它的帮助多于阻碍 :-) 与大多数生活一样,需要权衡取舍。
    【解决方案2】:

    我不会太担心额外的加入。以我的经验,当您连接大型数据集时,连接会造成巨大的性能损失。据推测,您的消息视图将显示 20-100 行顶部。

    但有一件事 - 如果您不需要左连接,只需使用常规连接。与常规连接相比,左连接需要花费大量额外时间。

    如果您真的很好奇,可以设置一个基准。 PHPMyAdmin 告诉您查询运行了多长时间;您可以检查有无最终加入的时间。 (请记住,所有 phpmyadmin 选择查询都是有限的,因此如果您选择的行数超过 20 行,则可能需要更长的执行时间。

    【讨论】:

    • phpMyAdmin 不是适合此类工作的工具。您应该使用 EMS MySQL Manager、Navicat for MySQL 等桌面工具。
    • 如果您需要来自两个大型数据集的数据,JOINS 通常是最有效的获取方式。
    • 我有 Sequel Pro,它在测试性能方面效果很好 - 我不知道 LEFT JOIN 比 JOIN 成本更高 - 我肯定要回去并在整个过程中替换很多 LEFT JOIN 语句我的代码。
    【解决方案3】:

    这个问题没有简单的答案。连接成本因可用索引、记录数量和许多其他因素而有很大差异。 MySQL 中的 AFAIR 至少有几个连接策略,按照从最好到最坏的情况排序。

    在实践中,您需要根据有关数据安全性的一般规则来制作架构 - 因此,请在需要时对您的数据库进行规范化。

    只有当您遇到真正的性能问题并且没有其他方法可以解决它(例如,添加索引、更改参数、重写查询......)时,才应该进行非规范化,并且应该基于对问题。

    【讨论】:

      【解决方案4】:

      根据我的经验,查询中额外的 JOIN 段的影响通常不会影响应用程序的成败。索引、避免子查询以及有时避免 LEFT JOIN 语句将产生最大的影响。

      正如 Sam Dufel 所提到的,设置一个基准来查看您正在使用的 LEFT JOIN 是否应该得到解决。生成一堆虚拟数据以查看它是否随着 JOIN 中记录数量的增加而扩展也可能很有用。

      【讨论】:

        【解决方案5】:

        联接是一种提高查询效率的策略。与另一个回应相反,在我有机会编写文本的每个产品中,外连接与内连接一样有效,其中包括 MySQL(两个主要引擎)、SQL Server、Sybase 和 Oracle。

        要避免的是子查询(主要是相关的子查询),这是常用的替代方法。

        【讨论】:

          【解决方案6】:

          总是更喜欢规范化。令我震惊的是,非规范化仍然受到这种关注。

          NORMALIZE - 这就是数据库引擎的优化目标。

          【讨论】:

          • 谢谢兰迪,我质疑它的唯一原因是阅读有关 Twitter 非规范化的信息。
          • 是的——我可能反应过度了。但是在您证明您的正确规范化系统存在问题之前,您甚至不应该考虑它。
          【解决方案7】:

          回答有关联接成本有多大的问题是不可能的,也没有用处。

          连接只是 SQL 查询中的一个命令,数据库对该连接的作用是完全不同的。查询中代价高昂的是表扫描之类的事情,其中​​数据库必须读取整个表才能找到一些数据。在有有用索引的表上进行十个连接的查询比在没有任何有用索引的单个表上查询要快得多。

          查询中的三个或四个连接当然不是对表进行反规范化以尝试提高性能的任何理由。作为比较;对于我们的网站,我们使用非规范化的表来读取数据,因为我们需要大约 40 个连接来收集我们需要的数据。

          【讨论】:

            猜你喜欢
            • 2011-09-06
            • 1970-01-01
            • 1970-01-01
            • 2015-10-29
            • 2011-07-23
            • 2015-10-19
            • 1970-01-01
            • 2016-08-26
            • 1970-01-01
            相关资源
            最近更新 更多