2014-12-05 177 views
0

我有一个获取用户详细信息的函数,并返回一个由每个用户数组和其相关数据组成的关联数组。我的函数的工作原理除了当它必须从mySQL中获取大量行时不起作用。如何在PHP的foreach循环中优化大型mySQL?

function function_name($DB, $id) 
{ 
    //Prepare, bind and execute statements 
    //Returns one value or an array 
} 

function main_function($DB, $id_list) 
{ 
    foreach($id_list as $user_id) 
    { 
     //Calls function_name 
     $data = function_name($DB, $user_id); 
    } 

    //Returns a nested associative array 
} 

有人告诉我,我应该移动绑定PARAM语句在我的情况foreach循环之外,但我已尽力,我不断收到错误“MySQL已经走了”的消息。当我可能一次查询10,000个ID时,如何优化从mysql查询?

请参考下面的代码片段进行详细说明。

function getUserEvent($DB_3308, $user_id) 
{ 
    $user_event = array(); 

    $sql_get_user_event = "SELECT * FROM user_event WHERE user_id = ?"; 

    $statement_user_event = $DB_PUMA_3306->link->prepare ($sql_get_user_event); 
    $statement_user_event ->bind_param ("s", $user_id); 
    $statement_user_event ->execute(); 

    if ($rs_user_event = $statement_user_event->get_result()) 
    { 
     while ($row = $rs_user_event->fetch_assoc()) 
     { 
      $user_event [] = $row; 
     } 
    } 

    return $user_event; 
} 

function getUserDetails($DB_3306, $DB_3308, $user_list) 
{ 
    $user_details = array(); 

    foreach ($user_list as $user_id) 
    { 
     $temp = array();  
     $user_personal = null; 
     $user_event = null; 

     $user_personal = getUserContact ($DB_3306, $user_id); 
     $user_event = getUserEvent($DB_3308, $userid); 

     $temp ['user_id'] = $user_id; 
     $temp ['full_name'] = $user_personal ['full_name']; 
     $temp ['tel_no'] = $user_personal ['tel_no']; 
     $temp ['email'] = $user_personal ['email']; 
     $temp ['events'] = $user_event ; 


     $user_details [] = $temp; 
    } 

    return $user_details; 
} 
+1

如果它显示那么为什么不使用分页? – 2014-12-05 07:16:07

+1

@AbhikChakraborty - 对不起,我不确定你的意思是分页。 – Cryssie 2014-12-05 07:16:51

+0

我的意思是,如果你有一个显示页面,你从数据库列出所有用户,你可以选择第一次显示100分页,检查这个链接我的意思是分页http://www.datatables.net /examples/basic_init/alt_pagination.html – 2014-12-05 07:22:52

回答

1

您似乎周围循环(可能)10000个用户和为每一个执行至少2个查询。每个查询都有一个小的头部来解析它,等等,因此有大量的查询可以快速加起来。

我建议,如果可能的话,你合并2个查询一起,做了一个连接以同时获得用户的联系方式和用户事件的详细信息。

我也建议你曾经在总每个用户ID执行此单查询所有用户ID,而不是一次。通常情况下,使用IN与用户ID列表很容易,但使用10000时,这并不是真正可行的。这样生成一个包含用户标识列表的临时表。

非常粗略地(并且使你的数据库类和实际数据的假设)是这样的: -

function getUserDetails($DB_3306, $DB_3308, $user_list) 
{ 

    $sql = 'CREATE TEMPORARY TABLE user_list_tmp 
      (
       user_id INT 
      )'; 

    $DB_3306->execute($sql); 

    $user_list_split = array_chunk($user_list, 250); 

    foreach($user_list_split as $user_list_split_chunk); 
    { 
     $sql = 'INSERT INTO user_list_tmp (user_id) VALUES ('.implode('),(', $user_list_split_chunk).')'; 
     $DB_3306->execute($sql); 
    } 

    $sql = "SELECT a.user_id, b.full_name, b.tel_no, b.email, c.event_id 
      FROM user_list_tmp a 
      INNER JOIN user_contact b 
      ON a.user_id = b.user_id 
      LEFT OUTER JOIN user_event c 
      ON a.user_id = c.userid 
      WHERE user_id = ? 
      ORDER BY a.user_id, c.event_id"; 

    $statement_user_event = $DB_3306->link->prepare ($sql); 
    $statement_user_event ->execute(); 

    $user_details = array(); 

    if ($rs_details = $statement_user_event->get_result()) 
    { 
     while ($row = $rs_details->fetch_assoc()) 
     { 
      $user_details[$row['user_id']]['user_id'] = $row['user_id']; 
      $user_details[$row['user_id']]['full_name'] = $row['full_name']; 
      $user_details[$row['user_id']]['tel_no'] = $row['tel_no']; 
      $user_details[$row['user_id']]['email'] = $row['email']; 
      $user_details[$row['user_id']]['events'][] = $row['event_id']; 
     } 
    } 
    return $user_details; 
} 

这需要你通过用户ID阵列,大块成250阵列,将它们插入到一个临时表(我倾向于批量插入250作为可读和快速插入语句之间的合理平衡,并执行最少数量的单独语句 - 您可以选择将其分成更大或更小的块)。

然后,它执行的是加入了临时表对表user_contact单个查询和左加入它针对user_event表。每个用户将返回多行,每一行甚至一行(但如果没有事件,仍然是一行)。它将这些放入一个数组中,并且通过使用user_id作为数组的键,我在此欺骗了一下。因此,对于用户ID的第一行,它将保存用户的详细信息,并在用户的任何后续行(对于其他事件)中保存用户详细信息,然后将自己写入。事件细节只是放入该用户的事件数组的下一个数组成员中。

1

你为什么不能获取从数据库之前得到数组一些50或100的用户ID,并把它拿来大量减少更多的查询负载?

$implodedUserIDs = implode(',', $userIDs); 
$query = "SELECT * FROM user_event WHERE user_id IN ($implodedUserIDs)"; 

它会减少一些负载。你也可以在每个负载中进行一些睡眠。试着尽可能地优化你的代码。 :)

+0

这是我想尝试的一件事,但我被告知使用“SELECT .. WHERE ... IN”会增加mysql的工作量。我不明白这一点吗? – Cryssie 2014-12-05 07:24:14

+0

如果您使用它,它会减少查询的数量。请尝试一次..你可以看到在加载时间差异.. – 2014-12-05 07:25:01

+0

非常感谢。我会试试看。 – Cryssie 2014-12-05 07:25:58