phpでmysqlデータベースの非同期クエリを実装

高洛峰
リリース: 2016-11-29 09:37:47
オリジナル
1264 人が閲覧しました

問題

通常、Web アプリケーションのパフォーマンスのボトルネックはデータベースです。通常、php の mysql クエリはシリアルであるためです。つまり、2 つの SQL ステートメントが指定されている場合、2 番目の SQL ステートメントは、最初の SQL ステートメントが実行されるまで待機してから実行されます。このとき、2つのSQL文を実行した場合、それぞれの実行時間は50msとなり、実行完了までに100msかかる場合があります。なぜなら、主な理由は SQL のシリアル実行によって引き起こされるからです。では、実行方法を変更してパフォーマンスを向上させることはできるのでしょうか?答えは「はい」です。非同期実行によりパフォーマンスを向上させることができます。

非同期

非同期で実行すると、パフォーマンスが大幅に向上する可能性があります。非同期方式を使用した場合、2 つの SQL ステートメントが同時に実行され、実行が完了するまでに 60 ミリ秒かかる場合があります。

実装

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 データベースの負荷が高くない場合でも、非同期クエリを使用することは良い選択です。


関連ラベル:
php
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート