【问题标题】:Read multiple records given array of record IDs from the database efficiently从数据库中有效地读取给定记录 ID 数组的多条记录
【发布时间】:2009-07-30 09:11:52
【问题描述】:

如果您的应用程序代码中有一组记录 ID,那么从数据库中读取记录的最佳方法是什么?

$idNumsIWant = {2,4,5,7,9,23,56};

显然循环遍历每个 ID 是不好的,因为您执行 n 个查询:

foreach ($idNumsIWant as $memID) {
    $DBinfo = mysql_fetch_assoc(mysql_query("SELECT * FROM members WHERE mem_id = '$memID'"));
    echo "{$DBinfo['fname']}\n";
}

那么,也许使用单个查询会更好?

$sqlResult = mysql_query("SELECT * FROM members WHERE mem_id IN (".join(",",$idNumsIWant).")");
while ($DBinfo = mysql_fetch_assoc($sqlResult))
  echo "{$DBinfo['fname']}\n";

但是当数组有 30,000 个元素时,这种方法是否可以缩放?

你如何有效地解决这个问题?

【问题讨论】:

    标签: php mysql database performance


    【解决方案1】:

    最佳方法最终取决于阵列中的 ID 数量(您显然不希望向服务器发送 50MB 的 SQL 查询,尽管从技术上讲,它可能能够轻松处理它而没有太多麻烦),但主要是关于如何处理结果行。

    • 如果 ID 的数量非常少(比如说几千个),使用 IN 语法的 WHERE 子句的单个查询将是完美的。您的 SQL 查询将足够短,以便将其可靠、高效且快速地传输到数据库服务器。这种方法非常适合单线程循环遍历结果记录。

    • 如果 ID 的数量真的很大,我建议你将 IDs 数组分成几组,并运行多个查询,每个查询都有一组 ID。对于 DB 服务器来说可能有点重,但在应用程序端,您可以生成多个线程并在多个记录集到达后立即以并行方式处理它们。

    这两种方法都可以。

    Cliffnotes :对于这种情况,只要数据提取不是太大的瓶颈,就应该关注数据的使用。并分析您的应用!

    【讨论】:

      【解决方案2】:

      我的想法:

      第一种方法在处理和磁盘读取方面成本太高。

      第二种方法效率更高,您不必太担心query size limit(但还是要检查一下)。

      【讨论】:

        【解决方案3】:

        当我不得不处理这种情况时,我至少看到了三到四种可能的解决方案:

        • 每个 id 一个请求;正如你所说,这不是很好:很多请求;我一般不这样做
        • 使用您提出的解决方案:一个请求多个 id
          • 但是你不能用很长的 id 列表来做到这一点:一些数据库引擎对你可以在 IN() 中传递的数据数量有限制
          • IN() 中的一个非常大的列表在性能方面可能不是很好
          • 所以我通常会做一个请求 X id 之类的操作,然后重复此操作。例如,要获取对应于 1000 个 id 的数据,我可以执行 20 个请求,每个请求获取 50 个 id 的数据 (这只是一个示例:针对您的特定情况,对您的数据库/表进行基准测试可能很有趣,因为它可能取决于几个因素)
        • 在某些情况下,您还可以重新考虑您的请求:也许您可以通过使用某种连接来避免传递这样的 id 列表? (这真的取决于你需要什么,你的表的架构,...)

        另外,为了方便修改获取逻辑,我会写一个函数来获取id列表,并返回对应的数据列表。

        这样,您只需以相同的方式调用此函数,并且始终获得相同的数据,而不必担心如何获取数据;这将允许您在需要时更改获取方法(如果有一天您发现另一种更好的方法),而不会破坏任何东西:函数的工作方式将改变,但由于它的接口(输入/输出)将保持不变,它不会为您的其余代码更改一个东西:-)

        【讨论】:

          【解决方案4】:

          如果是我,并且我有这么大的 in 子句值列表,我会使用存储过程和包含我想要的值的变量,并使用其中的函数将它们发送到临时表中,然后加入它。根据您要发送的值的大小,您可能需要将其拆分为多个输入变量以进行处理。有什么方法可以将值永久存储在数据库中(如果他们经常对此进行查询)?用户如何挑选出 30,000 个值,他或她肯定不会全部输入?因此,可能有更好的方法来基于连接和 where 子句查询表。

          【讨论】:

            【解决方案5】:

            使用 StringTokenizer 将你的字符串分成标记,这样你会更容易处理这个,检索多个值的数据

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-07-02
              • 1970-01-01
              • 1970-01-01
              • 2012-03-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多