PHP에서 mysql 데이터베이스의 비동기 쿼리 구현

高洛峰
풀어 주다: 2016-11-29 09:37:47
원래의
1264명이 탐색했습니다.

문제

일반적으로 웹 애플리케이션의 성능 병목 현상은 데이터베이스입니다. 왜냐하면 일반적으로 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 데이터베이스 로드가 높지 않은 경우에도 비동기 쿼리를 사용하는 것이 좋습니다.


관련 라벨:
php
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿