从数据库中有效地读取给定记录ID数组的多个记录

时间:2009-07-30 09:11:53

标签: php mysql database performance

如果您的应用程序代码中有一个记录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个元素时,这个方法是否可以扩展?

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

5 个答案:

答案 0 :(得分:2)

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

  • 如果ID的数量非常少(假设数千个顶部),使用IN语法的WHERE子句的单个查询将是完美的。您的SQL查询将足够短,以便可靠,高效,快速地传输到数据库服务器。此方法非常适合循环生成记录的单个线程。

  • 如果ID的数量非常大,我建议您将ID数组拆分为多个组,并运行多个查询,每个查询都有一组ID。对于数据库服务器来说可能有点重,但在应用程序端,您可以产生多个线程,并在它们到达时以平行的方式处理多个记录集。

这两种方法都有效。

Cliffnotes:对于这种情况,只要数据提取不是一个很大的瓶颈,就要关注数据的使用。并介绍您的应用程序!

答案 1 :(得分:1)

我的想法:

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

第二种方法效率更高,您不必担心query size limit(但无论如何都要检查)。

答案 2 :(得分:1)

当我必须处理这种情况时,我发现至少有三到四种可能的解决方案:

  • 每个id一个请求;正如你所说,这不是很好:很多要求;我一般不这样做
  • 使用您提出的解决方案:一个请求许多ID
    • 但是你不能用很长的id列表来做到这一点:某些数据库引擎对IN()
    • 中可以传递的数据数量有限制
    • IN()中的一个非常大的列表可能不是很好的表现
    • 所以我通常会做一个像X ID的请求,然后重复一遍。例如,为了确定对应于1000个ID的数据,我可以执行20个请求,每个请求获取50个的数据(这只是一个示例:对您的数据库/表进行基准测试可能很有意义,因为它可能取决于您的具体情况关于几个因素)
  • 在某些情况下,您还可以重新考虑您的请求:也许您可以通过使用某种联接来避免传递这样的ID列表? (这实际上取决于您的需求,您的表格架构......)

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

通过将字符串分成标记来使用StringTokenizer,您可以更轻松地处理此问题,检索多个值的数据