Problem
Normalerweise ist der Leistungsengpass einer Webanwendung die Datenbank. Denn normalerweise sind MySQL-Abfragen in PHP seriell. Das heißt, wenn zwei SQL-Anweisungen angegeben sind, wartet die zweite SQL-Anweisung, bis die erste SQL-Anweisung ausgeführt wird, bevor sie diese ausführt. Wenn zu diesem Zeitpunkt zwei SQL-Anweisungen ausgeführt werden, beträgt jede Ausführungszeit 50 ms und es kann 100 ms dauern, bis die Ausführung abgeschlossen ist. Da der Hauptgrund in der seriellen Ausführung von SQL liegt. Können wir also die Ausführungsmethode ändern, um die Leistung zu verbessern? Die Antwort lautet: Ja. Wir können die Leistung durch asynchrone Ausführung verbessern.
Asynchron
Bei asynchroner Ausführung kann die Leistung erheblich verbessert werden. Wenn die asynchrone Methode verwendet wird, werden die beiden SQL-Anweisungen gleichzeitig ausgeführt und es kann 60 ms dauern, bis die Ausführung abgeschlossen ist.
Implementieren Sie
mysqli mysqlnd. Die asynchrone Abfragemethode wird in mysqlnd bereitgestellt und offiziell von PHP implementiert. Dies sind:
mysqlnd_async_query sendet eine Abfrageanforderung
mysqlnd_reap_async_query erhält die Abfrageergebnisse
Auf diese Weise müssen Sie nicht jedes Mal blockieren und auf die Abfrageergebnisse warten, nachdem Sie die Abfrageanforderung gesendet haben.
Der Implementierungscode lautet wie folgt:
<!--?php $host = '127.0.0.1'; $user = 'root'; $password = ''; $database = 'test'; /** * 期望得到额结果 * 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('value'=>$key, 'link'=>$obj); } $done = 0; $total = count($links); foreach ($links as $value) { $value['link']->query("SELECT COUNT(*) AS `total` FROM `demo` WHERE `value`={$value['value']}", MYSQLI_ASYNC); } do { $tmp = array(); foreach ($links as $value) { $tmp[] = $value['link']; } $read = $errors = $reject = $tmp; $re = mysqli_poll($read, $errors, $reject, 1); if (false === $re) { die('mysqli_poll failed'); } 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]['value']; $result[$key_in_result] = $sql_result_array['total']; } 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['link']; echo "\n";
Fazit
Mysql-Datenbank startet einen separaten Thread für die Verarbeitung jeder Abfrageanforderung. Wenn der MySQL-Server zu viele Threads startet, führt der Threadwechsel zwangsläufig zu einer hohen Systemlast. Wenn die Auslastung der MySQL-Datenbank nicht hoch ist, ist die Verwendung einer asynchronen Abfrage immer noch eine gute Wahl.
Referenzdokument
http://www.walu.cc/php/async-mysql-query.md