首頁  >  文章  >  後端開發  >  php中mysql資料庫異步查詢實現

php中mysql資料庫異步查詢實現

高洛峰
高洛峰原創
2016-11-29 09:37:471203瀏覽

問題

通常一個web應用的效能瓶頸在資料庫。因為,通常情況下php中mysql查詢是串列的。也就是說,如果指定兩個sql語句時,第二個sql語句會等到第一個sql語句執行完畢再去執行。這時候,如果執行2個sql語句,每個執行時間為50ms,全部執行完畢可能需要100ms。既然,主要原因是sql的串列執行導致。那我們是不是可以改變執行方式來提升效能呢?答案是,可以的。我們可以透過非同步執行的方式來提高效能。

非同步

如果透過非同步的方式去執行,可能效能會有很大提升。如果是採用非同步的方式,兩個sql語句會並發執行,可能就需要60ms就可以執行完畢。

實作

mysqli + mysqlnd。 php官方實作的mysqlnd中提供了非同步查詢的方法。分別是:
mysqlnd_async_query 發送查詢請求
mysqlnd_reap_async_query 取得查詢結果
這樣就可以不必每次發送完查詢請求後,一直阻塞等待查詢結果了。

實作程式碼如下:

<!--?php
   
$host       = &#39;127.0.0.1&#39;;
$user       = &#39;root&#39;;
$password   = &#39;&#39;;
$database   = &#39;test&#39;;
   
/**
 * 期望得到额结果
 * array(
 *  1 =--> int,
 *  2 => int,
 *  3 => int
 * )
 */
$result = array(1=>0, 2=>0, 3=>0);
   
//异步方式[并发请求]
$time_start = microtime(true);
$links = array();
   
foreach ($result as $key=>$value) {
    $obj = new mysqli($host, $user, $password, $database);
    $links[spl_object_hash($obj)] = array(&#39;value&#39;=>$key, &#39;link&#39;=>$obj);
}
$done = 0;
$total = count($links);
   
foreach ($links as $value) {
    $value[&#39;link&#39;]->query("SELECT COUNT(*) AS `total` FROM `demo` WHERE `value`={$value[&#39;value&#39;]}", MYSQLI_ASYNC);
}
   
do {
   
    $tmp = array();
    foreach ($links as $value) {
        $tmp[] = $value[&#39;link&#39;];
    }
   
    $read = $errors = $reject = $tmp;
    $re = mysqli_poll($read, $errors, $reject, 1);
    if (false === $re) {
        die(&#39;mysqli_poll failed&#39;);
    } elseif ($re < 1) {
        continue;
    }
   
    foreach ($read as $link) {
        $sql_result = $link->reap_async_query();
        if (is_object($sql_result)) {
            $sql_result_array = $sql_result->fetch_array(MYSQLI_ASSOC);//只有一行
            $sql_result->free();
            $hash = spl_object_hash($link);
            $key_in_result = $links[$hash][&#39;value&#39;];
            $result[$key_in_result] = $sql_result_array[&#39;total&#39;];
        } else {
            echo $link->error, "\n";
        }
        $done++;
    }
   
    foreach ($errors as $link) {
        echo $link->error, "1\n";
        $done++;
    }
   
    foreach ($reject as $link) {
        printf("server is busy, client was rejected.\n", $link->connect_error, $link->error);
        //这个地方别再$done++了。
    }
} while ($done<$total);
var_dump($result);
echo "ASYNC_QUERY_TIME:", microtime(true)-$time_start, "\n";
   
$link = end($links);
$link = $link[&#39;link&#39;];
echo "\n";

結語

mysql資料庫對於每個查詢請求都是單獨啟動一個執行緒進行處理。如果mysql伺服器啟動執行緒過多,必然會造成執行緒切換造成系統負載過高。如果在mysql資料庫負載不高的情況下,使用非同步查詢還是不錯的選擇。


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn