如何在PHP的foreach循环中优化大型mySQL?

时间:2014-12-05 07:14:53

标签: php mysql foreach query-optimization

我有一个获取用户详细信息的函数,并返回一个关联数组,该数组由每个用户的数组及其相关数据组成。我的功能有效,只是当它必须从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
}

我被告知在我的情况下我应该在foreach循环之外移动bind param语句但是我已经尝试过并且我一直收到错误" MySQL已经消失了#34;信息。当我有可能一次查询10,0000个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;
}

2 个答案:

答案 0 :(得分:1)

为什么在从数据库中获取数据并在批量获取以减少更多查询负载之前,您是否无法在数组中获得50或100个userID?

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

它会减少一些负荷。你也可以在每次负荷时都睡一觉。只是尝试尽可能优化您的代码。 :)

答案 1 :(得分:1)

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

我建议如果可能的话,将两个查询合并在一起,进行连接以获取用户联系人详细信息和用户事件详细信息。

我还建议您对所有用户ID执行一次总计一次查询,而不是每个用户ID执行一次。通常情况下,使用带有用户ID列表的IN很容易,但使用10000时,这实际上并不可行。因此,生成一个包含用户ID列表的临时表。

非常粗略(并对数据库类和实际数据做出假设)如下: -

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作为数组的键进行了一些欺骗。因此,对于用户标识的第一行,它将保存用户的详细信息,并在用户的任何后续行(对于其他事件)中,用户详细信息将自行编写。事件详细信息只是放入该用户的events数组的下一个数组成员中。