SQL中的JOIN成本有多高?和/或,性能和规范化之间的权衡是什么?

时间:2011-04-24 22:19:24

标签: mysql sql performance join

我发现了一个类似的线程,但它并没有真正捕捉到我想要问的内容 - 所以我创建了一个新线程。

我知道在规范化和性能之间需要权衡,我想知道绘制这条线的最佳做法是什么?在我的特殊情况下,我有一个消息系统,它有三个不同的表:messages_threads(总体消息持有者),messages_recipients(涉及谁)和messages_messages(实际消息+时间戳)。

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

我的问题是:SQL中的JOINS对性能的代价是多少?例如,我可以在messages_threads表中名为“sendername”的字段下存储发件人的名称(我必须从用户那里继续加入) - 但就规范化而言,我一直被教导要避免数据冗余?

你在哪里划线?或者我是否高估了性能阻碍SQL连接的方式?

7 个答案:

答案 0 :(得分:21)

最佳做法是始终以3NF开头,然后如果发现特定的性能问题,则只考虑非规范化。

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

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

并且,请记住优化口头禅:测量,不要猜测!并在生产环境中进行测量。并且保持定期测量(和调整) - 如果您的模式和数据永远不会改变(非常不可能),优化只是一个设置和忘记操作。


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

答案 1 :(得分:3)

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

但有一件事 - 如果您不需要左连接,只需使用常规连接即可。左连接与常规连接需要相当多的额外时间。

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

答案 2 :(得分:3)

这个问题没有简单的答案。根据可用的索引,记录数量和许多其他因素,加入成本会有很大差异。 MySQL中的AFAIR至少有一些从最佳情况到最差情况排序的连接策略。

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

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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

要避免的是子查询(主要是相关子查询),它通常用作替代方案。

答案 5 :(得分:1)

总是喜欢正常化。令人震惊的是,非规范化STILL得到了这种关注。

NORMALIZE - 这就是数据库引擎的优化内容。

答案 6 :(得分:1)

回答有关加入费用的问题是不可能或有用的。

连接只是SQL查询中的一个命令,数据库对该连接的作用完全不同。查询中的代价是像表扫描这样的东西,数据库必须读取整个表来查找某些数据。在有有用索引的表上有10个连接的查询可以比没有任何有用索引的单个表上的查询快得多。

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