【问题标题】:JOINS vs. while statementsJOINS 与 while 语句
【发布时间】:2011-11-15 11:48:58
【问题描述】:

在我来工作的公司,他们运行一个 PHP/MySQL 关系数据库。我一直认为,如果我需要从不同的表中提取不同的信息,我可以做一个简单的连接来提取数据,例如......

SELECT table_1.id, table_2.id FROM table_1 LEFT JOIN table_2 ON table_1.sub_id = table_2.id

当我到达我目前工作的地方时,他们就是这样做的。

<?php $query = mysql_query("SELECT sub_id FROM table_1");
while($rs = mysql_fetch_assoc($query)) {
    $query_2 = mysql_fetch_assoc(mysql_query("SELECT * FROM table_2 WHERE id = '{$rs['sub_id']}'"));
    //blah blah blah more queries
?>

当我问为什么采用第二种方式时,他们说它实际上比连接运行得更快。他们管理的数据库在不同的表上有数百万条记录,其中一些表有点宽(按行)。他们说他们希望避免在执行不佳的查询可能锁定一个表(或其中几个)的情况下进行连接。要记住的另一件事是,此数据库附带一个庞大的报表生成器,客户可以使用它来构建自己的报表,如果他们发疯并构建大型报表,可能会造成严重破坏。

我很困惑,所以我想我会把它扔给普通的编程公众。这可能是一个见仁见智的问题,但是执行 while 语句(一个更大的查询来拉出很多行,如果你愿意的话,接着是很多小的小子查询)或进行连接(拉一次更大的查询以获取您需要的所有数据)。只要索引做得正确,这有关系吗?要考虑的另一件事是当前数据库是 InnoDB 格式。

谢谢!

2014 年 8 月 28 日更新

所以我想我会对此进行更新,以及更长期有效的方法。经过这次讨论,我决定在工作中重建报告生成器。我没有确切的结果数字,但我想我会分享结果。

我认为这有点矫枉过正,因为我将整个报告(就返回的数据而言,它是非常动态的)变成了一个大规模的加入盛宴。大多数连接(如果不是全部连接)都将值连接到主键,因此它们都运行得非常快。如果报表有 30 列数据要提取并且它提取了 2000 条记录,那么每个字段都在运行查询以获取数据(因为该数据可能位于不同的字段中)。 30 x 2000 = 60000,即使在每次查询 0.0003 秒的甜蜜查询时间下,这仍然是 18 秒的查询时间(这几乎是我记得的时间)。现在我将查询重建为一堆主键上的大规模连接(如果可能),相同的报告在大约 2-3 秒内加载,大部分时间都在下载 html。根据所需数据,返回的每条记录都会运行 0-4 个额外查询(如果它可以在连接中获取数据,则可能不需要任何数据,这种情况发生在 75% 的时间)。因此,同样的 2000 条记录将返回额外的 0-8000 条查询(比 60000 条要好得多)。

我会说 while 语句在某些情况下很有用,但正如下面在 cmets 中所述,基准测试就是它的全部意义所在。就我而言,join 是更好的选择,但在我网站的其他区域,while 语句更有用。在一个例子中,我有一份报告,其中客户可以请求几个类别来拉取并且只返回这些类别的数据。发生的事情是我有一个带有 50-500 个 ID 的 category_id IN(...,...,..,.., etc etc etc),当我在最后时刻拿着它时,索引会窒息并死在我的怀里。所以我所做的是将 id 分成 10 个一组展开,并运行相同的查询 x / 10 次,我的结果比以前更快地获取 方式,因为索引喜欢处理 10 个 ID,而不是 500 个,所以我看到我的查询有了很大的改进,因为执行了 while 语句。

【问题讨论】:

  • 对其进行基准测试。你的同事不会因为网上有人说他们错了而改变主意。想出一个像样的测试用例,并尝试两种方式。但是,如果您可以向他们展示确切的数字,他们怎么能反对呢?

标签: php mysql join while-loop


【解决方案1】:

如果正确使用索引,那么使用 JOIN 几乎总是更有效。之所以要强调,是因为最佳效率并不总是等于最佳性能。

但实际上并没有万能的答案;您应该使用EXPLAIN 分析查询,以确保确实使用了索引,没有使用不必要的临时表等。在某些情况下,条件会共同创建一个查询,该查询只是 不能使用索引。在这些情况下,可能按照您指定的方式将查询分成几部分会更快。

如果我在现有项目中遇到这样的代码,我会提出质疑:检查查询,考虑执行查询的不同方法,确保已考虑这些事项,为或构建一个科学的、有事实依据的案例反对这种做法。确保最初的开发人员尽职尽责,因为不使用 JOIN 表面上指向糟糕的数据库或查询设计。最后,虽然结果很响亮,如果所有优化和更正仍然导致连接速度比使用查询片段提供的速度慢,那么更快的解决方案占上风。对基准结果进行基准测试并采取行动;在软件设计中,没有任何情况下你应该用糟糕的性能来换取遵守关于你应该做什么或不应该做什么的任意规则。效果最好的方法就是最好的方法。

【讨论】:

    【解决方案2】:

    如果索引放置得当,最好进行大查询。

    背后的逻辑:

    • 1 次查询 = 1 次调用数据库服务器,然后处理查询(优化器和所有)并最终返回结果。 N 次查询意味着对数据库的 N 次调用,包括对优化器的 N 次调用,以及在糟糕情况下的 I/O。
    • MySQL 对 JOIN 进行了优化。如果您再做一段时间,这些优化将无法发挥作用。

    如前面的答案所述,如果您使用 JOIN,请检查 EXPLAIN 是否存在未使用索引的内容。此外,您应该检查分配给 InnoDB 缓存的内存,以及分配给 MySQL 以解析给定查询的内存。可能是因为这些参数,数据库在执行 JOIN 时变慢了。

    【讨论】:

      【解决方案3】:

      我会说答案是,这取决于。通常,我会说连接就是答案,并且在循环中执行多个查询是不好的做法,但是,这完全取决于正在执行的操作。

      你是这样的吗?如果没有详细的表结构和索引信息以及外键的使用等,我们无法确定。如果你想检查,最好的主意是试试看。获取他们的查询,解释它们,编写您自己的查询,然后对此进行解释,看看哪个更有效。

      【讨论】:

        【解决方案4】:

        我不确定大型数据库,但在我的项目中,我总是尽量减少查询。查询使用硬盘访问和(如果不在同一主机上)网络访问,这很慢。如果第一个查询中有很多条目,您可能会在每页运行数千个查询,这会很慢。

        【讨论】:

          【解决方案5】:

          基准测试以找出实际答案。

          对于您提供的示例,(使用等效数据)数据库连接使用的资源极不可能比设置新连接并执行完全相同的操作(毕竟:您仍在连接数据以与连接相同的方式进行,即使它是在外部完成的):如果是,则可以简单地重写引擎以使用该外部路由来提高性能。

          当连接使用更多资源时(除了索引问题),它主要来自于每行检索数据的缺点,这意味着父表的信息将在每一行中重复,即使这是冗余的。

          这可能会导致性能问题,如果出现以下情况,可以通过拆分查询来解决:

          1. 一个父母有很多孩子并且
          2. 您从父级获取大量数据(许多列或大型字段)

          根据我的经验,减少查询数量几乎总能提高性能(我通过组合查询进行优化,而不是分开查询)。

          正确使用索引当然是个好建议,但乍一看,我认为这并不能解释这两种情况之间的差异,因为相同的索引(或缺少)将适用于两种情况。

          【讨论】:

            猜你喜欢
            • 2017-03-08
            • 2016-02-29
            • 2020-05-25
            • 2012-02-07
            • 2022-01-17
            • 2016-01-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多