PHP / MySQL - 同时进行多个查询

时间:2014-01-05 03:00:23

标签: php mysql sql database

我有24个数据库,其中有一个标有email_queue的表格。

我有另一个数据库,其中包含所有包含email_queue表的数据库的列表。

我遍历数据库列表并查询我的email_queue表以发送每个数据库的邮件。

这个问题是,php脚本在第三个数据库被阻止,发送500封电子邮件,而其他数据库在那之后等待轮到他们。

我试图找出如何同时查询所有24个数据库并同时发送电子邮件队列。

有什么建议吗?

3 个答案:

答案 0 :(得分:4)

我认为拥有这么多数据库可能是糟糕设计的标志。如果你不能改变它并且现在需要继续前进,我建议选择以下两个选项之一:

  1. 使用参数运行相同的脚本以选择要使用的数据库。您应该能够找到有关如何执行此操作的资源
  2. 使用非阻止查询;这个答案的其余部分将用于讨论这个问题。
  3. 这是一个使用mysqli扩展(需要mysqlnd驱动程序)的完整示例:

    $credentials = array(
        array(
            'host' => 'host1',
            'user' => 'user',
            'password' => 'password',
            'database' => 'database'
        ),
        array(
            'host' => 'host2',
            'user' => 'user',
            'password' => 'password',
            'database' => 'database'
        ),
        // credentials for other sites
    );
    $dbcs = array();
    foreach ($credentials as $config) {
        $dbcs[] = array($db = new mysqli(
            $config['host'],
            $config['user'],
            $config['pass'],
            $config['database']
        ));
        $query = ""; // here is your query to do whatever it is with your table
        $db->query($query, MYSQLI_ASYNC);
    }
    
    $results = array();
    $errors = array();
    $rejected = array();
    $secondsToWait = 1;
    
    while (!empty($dbcs)) {
        foreach ($dbcs as $key => $c) {
            $db = $c[0];
            if (mysqli_poll($c, $errors, $rejected, $secondsToWait) == 1) {
                $r = $db->reap_async_query();
    
                // here you would do your fetches for each query, such as
                $results[] = $r->fetch_assoc();
    
                // do what you need to do with the result
    
                // then cleanup
                $r->free();
                $db->close();
                unset($dbcs[$key]);
            }
        }
    }
    

    请注意,它确实有缺点,例如查询失败可能会导致整个程序崩溃。

答案 1 :(得分:2)

使用curl_multi_open

进行此操作

将你的脚本拆分为两个,你可以制作一个php文件(比如email_out.php)获取数据库名称(或者用于查找数据库名称的一些变量,交换机将在for循环中或者在email_out中.php),然后根据那个脚本做大量邮件。

第二部分使用curl_multi_open多次打开email_out.php脚本,有效地创建了与不同数据库的多个独立连接,这些脚本可以在不同的时间解析,因为它们都是并行运行的。 从本质上讲,你的循环现在使用不同的参数多次将curl_multi_open添加到脚本中,然后异步执行所有这些脚本。

class Fork
{
    private $_handles = array();
    private $_mh      = array();

    function __construct()
    {
        $this->_mh = curl_multi_init();
    }

    function add($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_multi_add_handle($this->_mh, $ch);
        $this->_handles[] = $ch;
        return $this;
    }

    function run()
    {
        $running=null;
        do {
            curl_multi_exec($this->_mh, $running);
            usleep (250000);
        } while ($running > 0);
        for($i=0; $i < count($this->_handles); $i++) {
            $out = curl_multi_getcontent($this->_handles[$i]);
            $data[$i] = json_decode($out);
            curl_multi_remove_handle($this->_mh, $this->_handles[$i]);
        }
        curl_multi_close($this->_mh);
        return $data;
    }
}

(来自http://gonzalo123.com/2010/10/11/speed-up-php-scripts-with-asynchronous-database-queries/

所以你的循环看起来像这样:

$fork = new Fork;
for ($i = 0; $i < 24; $i++) {
    $fork->add("email_out.php?t=" . $i);
}
$fork->run();

答案 2 :(得分:0)

在你的脚本中试试这个。

  1. 使用set_time_limit(0);覆盖PHP的max_execution_time
  2. 使用getopt()函数从命令行运行脚本时获取数据库名称(即php script.php -d database1)。
  3. 从那里做逻辑。
  4. 在您的crontab中,为每个要使用我在2中指定的开关(-d)发送电子邮件的数据库创建一个条目。如果您有20个数据库,那么您必须有20个条目。
  5. 使用这种方式,您将看到每个cron作业的单独PHP进程,如果您遇到错误,可以隔离数据库。