【问题标题】:Avoiding a query inside a loop in my situation在我的情况下避免在循环内进行查询
【发布时间】:2012-12-31 14:40:10
【问题描述】:

我这里的情况很复杂。如果不将 SELECT 查询放在一个循环中,当我进入该页面时,我找不到更好的方法来解决这个问题(别担心,我使用 array_chunk 将数组拆分为页面)。如果我在这里使用查询,我想这将是一个资源杀手。正因为如此,我在这里,问一个问题。

我有一个需要循环的大数组:

$images = scandir($imgit_root_path . '/' . IMAGES_PATH);

$indexhtm = array_search('index.htm', $images);
unset($images[0], $images[1], $images[$indexhtm]);

现在我的IMAGES_PATH 中有一个包含文件(图像)的所有文件名的数组。现在问题来了:

其中一些图像已在数据库中注册,因为注册用户的图像已在我的数据库中列出。现在我需要根据上面数组给我的图像名称检索user_id

在循环中我只是这样做了:

foreach ($images as $image_name)
{
    $query = $db->prepare('SELECT user_id FROM imgit_images WHERE image_name = :name');
    $query->bindValue(':name', $image_name, PDO::PARAM_STR);
    $query->execute();
    $row = $query->fetch(PDO::FETCH_ASSOC);
    $user_id = $row['user_id'];

    echo $user_id;
}

这工作得很好,但效率等于 0。使用 user_id 我计划从 imgit_users 表中获取其他内容,例如 username,这将需要在该循环中进行另一个查询。

这太多了,我需要一种更简单的方法来处理这个问题。

有没有办法在进入循环之前获取那些user_ids 并在循环中使用它们?

这是来自imgit_images 的表结构:

虽然这是imgit_users 的架构:

【问题讨论】:

  • 老实说,我想过这个问题,但是我又不知道如何在循环中使用带有 user_ids 的数组,然后也获取用户名。我怎么知道哪个image_name 适合user_id 与两个不同的数组?
  • 您可以选择user_idimage_name,这样在循环中,您就有了两者之间的关联。
  • Select image_name, user_id, username... for all 来自imgit_images 的记录,将其转换为以image_name 为索引的关联数组,将此数组推入更快的存储空间(例如memcached )。在页面加载时从 memcached 中获取它。仅在更改/添加某些图像时查询 MySQL 以刷新存储在 memcached 中的结果。
  • 根据这些 cmets 检查我的答案。

标签: php mysql loops select


【解决方案1】:

这样的事情会起作用(我不确定是否可以准备 WHERE IN 查询,因为值的数量是未知的......否则,确保你清理 $images ):

$image_names = "'".implode("', '", $images)."'";
$query = $db->prepare("SELECT img.user_id, image_name, username 
                         FROM imgit_images img
                         INNER JOIN imgit_users u ON u.user_id = img.user_id 
                         WHERE image_name IN(".$image_names.")");
$query->execute();
while($row = $query->fetch(PDO::FETCH_ASSOC))
{
    echo $row['user_id']."'s image is ".$row['image_name'];
}

你可能需要稍微调整一下(还没有测试过),但你似乎可以做到,所以我不担心!

【讨论】:

  • 嘿。它有点工作,但我的逻辑仍然被阻塞,我不知道如何检查主循环内部(我循环scandir()),如果循环中的image_name等于我们从查询中得到的image_name,所以我们可以将用户名添加到该图像。这是我创建的方法(基于您的查询)如何返回数组的示例:Array ( [user_id] => 4 [image_name] => 7E4c1i2.jpg [username] => DEATHMETALGORE )
  • 什么意思?如果image_names 不等于,它就不会出现在查询结果中!还是您的意思是要确保查询结果中的顺序与$images中的顺序一致?
  • 我让它工作了。我将添加一个 pastebin.com 链接,以显示我是如何做到的。非常感谢 mbinette
  • 太棒了!很高兴知道你已经成功了!你是怎么做到的? :-)
  • 这就是我的做法:pastebin.com/LbwzHMXg - 非常感谢,感谢您的帮助! :)
【解决方案2】:

不确定它是否会有所帮助,但我看到了一些可能的优化:

  1. 在循环外准备查询,在循环内反弹/执行/获取结果。如果查询准备成本很高,您可能会节省不少时间。

  2. 您可以像Passing an array to a query using a WHERE clause 一样传递一个数组并获取图像和用户ID,这样您就可以将您的查询分成较少数量的查询。

【讨论】:

    【解决方案3】:

    你能不能只在查询中使用INNER JOIN,这样循环的每次迭代都会返回相应用户的详细信息。将您的查询更改为类似(我在这里假设您的表结构):

    SELECT imgit_users.user_id 
    ,imgit_users.username
    ,imgit_users.other_column_and_so_on
    FROM imgit_images 
    INNER JOIN imgit_users ON imgit_users.user_id = imgit_images.user_id
    WHERE imgit_images.image_name = :name
    

    这显然不能避免循环的需要(您可能会使用字符串连接来构建 where 子句的 IN 部分,但无论如何您可能会在此处使用连接)但它会返回每次迭代的用户信息,并防止需要进一步迭代来获取用户信息。

    【讨论】:

      【解决方案4】:

      PDO 让您安全地编写查询变得轻而易举。

      $placeholders = implode(',', array_fill(0, count($images), '?'));
      $sql = "SELECT u.username 
              FROM imgit_images i
              INNER JOIN imgit_users u ON i.user_id = u.id
              WHERE i.image_name IN ({$placeholders})";
      $stmt = $db->prepare($sql);
      $stmt->execute($images);
      
      while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
          // use $row['username']
      }
      

      创建一串以逗号分隔的?s 并将它们写入IN 的括号中。然后将图像数组传递给execute()。轻松完成,现在您所有想要的数据都可以在单个查询的单个结果集中获得。 (根据需要向查询的 SELECT 子句添加其他列。)

      【讨论】:

        猜你喜欢
        • 2013-12-05
        • 2012-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-11
        • 1970-01-01
        • 2020-03-28
        • 2011-01-09
        相关资源
        最近更新 更多