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

如何在PHP中优化foreach循环中的大型mySQL?,php,mysql,foreach,query-optimization,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

我有一个函数,它获取用户详细信息并返回一个关联数组,该数组由每个用户的数组及其相关数据组成。我的函数可以工作,只是当它必须从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
}
有人告诉我,在我的例子中,应该将bind param语句移到foreach循环之外,但我已经尝试过了,并且不断收到错误消息“MySQL已经消失”。当我可能一次查询100000个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;
}

为什么在从数据库中获取50或100个用户ID并批量获取之前,不能在数组中获取这些用户ID以减少更多的查询负载

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

这将减少一些负载。此外,你还可以在每次负载时睡上一觉。只要尽可能地优化代码即可。:)

为什么在从数据库中获取50或100个用户ID之前,不能在数组中获取这些用户ID并批量获取以减少更多的查询负载

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

这将减少一些负载。此外,你还可以在每次负载时睡上一觉。只要尽可能地优化代码即可。:)

为什么在从数据库中获取50或100个用户ID之前,不能在数组中获取这些用户ID并批量获取以减少更多的查询负载

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

这将减少一些负载。此外,你还可以在每次负载时睡上一觉。只要尽可能地优化代码即可。:)

为什么在从数据库中获取50或100个用户ID之前,不能在数组中获取这些用户ID并批量获取以减少更多的查询负载

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

这将减少一些负载。此外,你还可以在每次负载时睡上一觉。只要尽可能地优化代码即可。:)

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

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

我还建议您对所有用户id总共执行一次查询,而不是对每个用户id执行一次查询。通常情况下,在使用用户id列表时很容易做到这一点,但对于10000个用户id来说,这是不可行的。因此,生成包含用户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个为一批插入,作为可读和快速插入语句与执行最少数量的单独语句之间的合理平衡-您可以选择将其分为更大或更小的块)


然后,它执行单个查询,将temp表与user\u contact表联接,并将其与user\u event表联接。每个用户将返回多行,每个偶数对应一行(但如果没有事件,则仍然返回一行)。它将这些数据放入一个数组中,我在这里使用了用户id作为数组的键,这有点作弊。因此,对于用户id的第一行,它将为用户保存详细信息,而对于用户的任何后续行(对于进一步的事件),用户详细信息都将重写它们自己。事件详细信息仅放入该用户的事件数组的下一个数组成员中。

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

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

我还建议您对所有用户id总共执行一次查询,而不是对每个用户id执行一次查询。通常情况下,在使用用户id列表时很容易做到这一点,但对于10000个用户id来说,这是不可行的。因此,生成包含用户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个为一批插入,作为可读和快速插入语句与执行最少数量的单独语句之间的合理平衡-您可以选择将其分为更大或更小的块)


然后,它执行单个查询,将temp表与user\u contact表联接,并将其与user\u event表联接。每个用户将返回多行,每个偶数对应一行(但如果没有事件,则仍然返回一行)。它将这些数据放入一个数组中,我在这里使用了用户id作为数组的键,这有点作弊。因此,对于用户id的第一行,它将为用户保存详细信息,而对于用户的任何后续行(对于进一步的事件),用户详细信息都将重写它们自己。事件详细信息仅放入该用户的事件数组的下一个数组成员中。

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

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

我还建议您对所有用户id总共执行一次查询,而不是对每个用户id执行一次查询。通常情况下,在使用用户id列表时很容易做到这一点,但对于10000个用户id来说,这是不可行的。因此,生成包含用户ID列表的临时表

非常粗略(并对数据库类和实际数据进行假设)