Heim  >  Artikel  >  Backend-Entwicklung  >  So fragen Sie MySQL gleichzeitig mit PHP ab

So fragen Sie MySQL gleichzeitig mit PHP ab

小云云
小云云Original
2018-01-30 10:28:172047Durchsuche

Ich habe kürzlich PHP studiert und es hat mir sehr gut gefallen. Ich bin auf das Problem der gleichzeitigen Abfrage von MySQL in PHP gestoßen. Jetzt werde ich es mit Ihnen teilen und als Referenz geben. Folgen wir dem Herausgeber und schauen wir uns das an. Ich hoffe, es kann allen helfen.

Synchronische Abfrage

Dies ist unser häufigster Aufrufmodus. Der Client ruft die Abfrage[Funktion] auf, initiiert einen Abfragebefehl, wartet auf die Rückgabe des Ergebnisses und liest das Ergebnis; sendet den zweiten Abfragebefehl, wartet auf die Rückgabe des Ergebnisses und liest das Ergebnis. Die insgesamt benötigte Zeit ist die Summe der Zeit der beiden Abfragen. Vereinfachen Sie den Prozess beispielsweise wie folgt:

Als Beispiel sind die Aufrufe einer Abfrage [Funktion] von 1.1 bis 1.3. Zwei Abfragen erfordern die Serialisierung von 1.1 , 1.2, 1.3, 2.1, 2.2, 2.3, insbesondere 1.2 und 2.2, blockieren das Warten und der Prozess kann keine anderen Dinge tun.

Der Vorteil des synchronen Aufrufs besteht darin, dass er unserem intuitiven Denken entspricht und einfach aufzurufen und zu verarbeiten ist. Der Nachteil besteht darin, dass der Prozess blockiert ist und auf die Rückgabe des Ergebnisses wartet, was die Laufzeit verlängert.
Kann die Wartezeit sinnvoll genutzt werden, um die Verarbeitungskapazität des Prozesses zu verbessern, wenn mehrere Abfrageanfragen vorliegen oder der Prozess andere Dinge zu erledigen hat?

Aufteilen

Jetzt teilen wir die Abfrage [Funktion] in Teile auf. Der Client kehrt sofort nach 1.1 zurück, der Client überspringt 1.2 und es gibt Daten in 1.3 die Daten nach Erreichen. Auf diese Weise wird der Prozess von der ursprünglichen 1.2-Stufe befreit und kann mehr Dinge tun, wie zum Beispiel ... eine weitere SQL-Abfrage initiieren [2.1]. Haben Sie den Prototyp einer gleichzeitigen Abfrage gesehen?

Gleichzeitige Abfrage

Im Vergleich zur synchronen Abfrage wird die nächste Abfrage initiiert, nachdem die vorherige Abfrage abgeschlossen ist. Die gleichzeitige Abfrage kann unmittelbar nach Initiierung der vorherigen Abfrageanforderung initiiert werden . Initiieren Sie die nächste Abfrageanforderung. Vereinfachen Sie den Prozess wie unten gezeigt:

Beispiel: Nach erfolgreichem Senden der Anfrage in 1.1.1 wird [1.1.2] sofort zurückgegeben und das endgültige Abfrageergebnis ist zurückgegeben in Distant 1.2. Zwischen 1.1.1 und 1.2 wurde jedoch eine weitere Abfrageanforderung initiiert. Während dieses Zeitraums kamen zwei Abfrageanforderungen gleichzeitig vor 1.2 an, sodass die Gesamtzeit der beiden Abfragen nur der Zeit von entsprach die erste Abfrage.

Der Vorteil der gleichzeitigen Abfrage besteht darin, dass sie die Nutzung des Prozesses verbessern, das Blockieren des Wartens auf die Verarbeitung der Abfrage durch den Server vermeiden und die Zeit mehrerer Abfragen verkürzen kann. Die Nachteile liegen aber auch auf der Hand. Um N gleichzeitige Abfragen zu initiieren, müssen N Datenbankverbindungen eingerichtet werden. Bei Anwendungen mit Datenbankverbindungspools kann diese Situation vermieden werden.

Degenerieren

Idealerweise möchten wir N Abfragen gleichzeitig ausführen, und der Gesamtzeitverbrauch entspricht der Abfrage mit der längsten Abfragezeit. Es ist aber auch möglich, dass gleichzeitige Abfragen zu synchronen Abfragen [degenerieren]. Was? Wenn im Beispielbild 1.2 vor 2.1.1 zurückgegeben wird, wird die gleichzeitige Abfrage [degeneriert] in [synchrone Abfrage], aber die Kosten sind höher als die der synchronen Abfrage.

Multiplexing

  • Abfrage1 initiieren

  • Abfrage2 initiieren

  • Abfrage3 initiieren

  • ......

  • Warten auf Abfrage1, Abfrage2, Abfrage3

  • Ergebnisse von Abfrage2 lesen

  • Ergebnisse von Abfrage1 lesen

  • Ergebnisse von Abfrage3 lesen

So Wie kann man warten und wissen, wann die Abfrageergebnisse zurückgegeben werden und welche Abfrageergebnisse zurückgegeben werden?

Bei jeder Abfrage IO lesen? Wenn es auf blockierende IOs stößt, wird es auf einem IO blockiert, und bei anderen IOs werden Ergebnisse zurückgegeben, die nicht verarbeitet werden können. Wenn es sich also um eine nicht blockierende E/A handelt, besteht kein Grund zur Sorge, dass eine der E/As blockiert wird. Dies ist zwar der Fall, führt jedoch zu kontinuierlichen Abfragen und Beurteilungen und verschwendet CPU-Ressourcen.

In dieser Situation können Sie Multiplexing verwenden, um mehrere IOs abzufragen.

PHP implementiert gleichzeitige Abfragen von MySQL

PHPs mysqli (mysqlnd-Treiber) bietet Multiplex-Polling-E/A (mysqli_poll) und asynchrone Abfragen (MYSQLI_ASYNC, mysqli_reap_async_query). Verwenden Sie diese beiden Funktionen, um Gleichzeitige Abfragen implementieren, Beispielcode:


<?php
 $sqls = array(
  &#39;SELECT * FROM `mz_table_1` LIMIT 1000,10&#39;,
  &#39;SELECT * FROM `mz_table_1` LIMIT 1010,10&#39;,
  &#39;SELECT * FROM `mz_table_1` LIMIT 1020,10&#39;,
  &#39;SELECT * FROM `mz_table_1` LIMIT 10000,10&#39;,
  &#39;SELECT * FROM `mz_table_2` LIMIT 1&#39;,
  &#39;SELECT * FROM `mz_table_2` LIMIT 5,1&#39;
 );
 $links = [];
 $tvs = microtime();
 $tv = explode(&#39; &#39;, $tvs);
 $start = $tv[1] * 1000 + (int)($tv[0] * 1000);
 // 链接数据库,并发起异步查询
 foreach ($sqls as $sql) { 
  $link = mysqli_connect(&#39;127.0.0.1&#39;, &#39;root&#39;, &#39;root&#39;, &#39;dbname&#39;, &#39;3306&#39;);
  $link->query($sql, MYSQLI_ASYNC); // 发起异步查询,立即返回
  $links[$link->thread_id] = $link;
 }
 $llen = count($links);
 $process = 0;
 do {
  $r_array = $e_array = $reject = $links;
  // 多路复用轮询IO
  if(!($ret = mysqli_poll($r_array, $e_array, $reject, 2))) {
   continue;
  }
  // 读取有结果返回的查询,处理结果
  foreach ($r_array as $link) {
   if ($result = $link->reap_async_query()) {
    print_r($result->fetch_row());
    if (is_object($result))
     mysqli_free_result($result);
   } else {
   }
   // 操作完后,把当前数据链接从待轮询集合中删除
   unset($links[$link->thread_id]);
   $link->close();
   $process++;
  }
  foreach ($e_array as $link) {
   die;
  }
  foreach ($reject as $link) {
   die;
  }
 }while($process < $llen);
 $tvs = microtime();
 $tv = explode(&#39; &#39;, $tvs);
 $end = $tv[1] * 1000 + (int)($tv[0] * 1000);
 echo $end - $start,PHP_EOL;

mysqli_poll-Quellcode:


#ifndef PHP_WIN32
#define php_select(m, r, w, e, t) select(m, r, w, e, t)
#else
#include "win32/select.h"
#endif
/* {{{ mysqlnd_poll */
PHPAPI enum_func_status
mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num)
{
 struct timeval tv;
 struct timeval *tv_p = NULL;
 fd_set   rfds, wfds, efds;
 php_socket_t max_fd = 0;
 int    retval, sets = 0;
 int    set_count, max_set_count = 0;
 DBG_ENTER("_mysqlnd_poll");
 if (sec < 0 || usec < 0) {
  php_error_docref(NULL, E_WARNING, "Negative values passed for sec and/or usec");
  DBG_RETURN(FAIL);
 }
 FD_ZERO(&rfds);
 FD_ZERO(&wfds);
 FD_ZERO(&efds);
 // 从所有mysqli链接中获取socket链接描述符
 if (r_array != NULL) {
  *dont_poll = mysqlnd_stream_array_check_for_readiness(r_array);
  set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd);
  if (set_count > max_set_count) {
   max_set_count = set_count;
  }
  sets += set_count;
 }
 // 从所有mysqli链接中获取socket链接描述符
 if (e_array != NULL) {
  set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd);
  if (set_count > max_set_count) {
   max_set_count = set_count;
  }
  sets += set_count;
 }
 if (!sets) {
  php_error_docref(NULL, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
  DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
  DBG_RETURN(FAIL);
 }
 PHP_SAFE_MAX_FD(max_fd, max_set_count);
 // select轮询阻塞时间
 if (usec > 999999) {
  tv.tv_sec = sec + (usec / 1000000);
  tv.tv_usec = usec % 1000000;
 } else {
  tv.tv_sec = sec;
  tv.tv_usec = usec;
 }
 tv_p = &tv;
 // 轮询,等待多个IO可读,php_select是select的宏定义
 retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);
 if (retval == -1) {
  php_error_docref(NULL, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
      errno, strerror(errno), max_fd);
  DBG_RETURN(FAIL);
 }
 if (r_array != NULL) {
  mysqlnd_stream_array_from_fd_set(r_array, &rfds);
 }
 if (e_array != NULL) {
  mysqlnd_stream_array_from_fd_set(e_array, &efds);
 }
 // 返回可操作的IO数量
 *desc_num = retval;
 DBG_RETURN(PASS);
}

Ergebnisse gleichzeitiger Abfragevorgänge

Um den Effekt intuitiver zu sehen, habe ich eine Tabelle mit 130 Millionen Datenmengen gefunden, die nicht für den Betrieb optimiert wurde.

Gleichzeitige Abfrageergebnisse:

Synchrone Abfrageergebnisse:

Von Von dem Ergebnisse: Der Gesamtzeitverbrauch der synchronen Abfrage ist die Summe der Zeit aller Abfragen, und der Gesamtzeitverbrauch der gleichzeitigen Abfrage ist tatsächlich die Abfrage mit der längsten Zeit (die vierte Abfragezeit der synchronen Abfrage beträgt einige Sekunden). mit dem Gesamtzeitaufwand gleichzeitiger Abfragen) und die Abfragereihenfolge gleichzeitiger Abfragen und die Reihenfolge, in der die Ergebnisse eintreffen, sind unterschiedlich.

Vergleich mehrerer Abfragen mit kürzeren Abfragezeiten

Verwenden Sie mehrere SQL-Abfragen mit kürzeren Abfragezeiten zum Vergleich

Testen Sie 1 der Ergebnisse gleichzeitiger Abfragen (Datenbank Linkzeit wird ebenfalls gezählt):

Synchrone Abfrageergebnisse (Datenbanklinkzeit wird ebenfalls gezählt):

Gleichzeitig Ergebnisse des Abfragetests 2 (die Datenbankverknüpfungszeit wird nicht gezählt):

Den Ergebnissen nach zu urteilen, hat Test 1 der gleichzeitigen Abfrage keinen Nutzen gebracht. Aus Sicht der synchronen Abfrage dauert jede Abfrage etwa 3-4 ms. Wenn die Datenbankverbindungszeit jedoch nicht in die Statistik einbezogen wird (synchrone Abfragen haben nur eine Datenbankverbindung), können die Vorteile gleichzeitiger Abfragen erneut zum Ausdruck kommen.

Fazit

Hier haben wir die Implementierung der gleichzeitigen Abfrage MySQL in PHP besprochen und anhand der experimentellen Ergebnisse intuitiv die Vor- und Nachteile der gleichzeitigen Abfrage verstanden. Die Zeit zum Aufbau einer Datenbankverbindung macht immer noch einen großen Teil einer optimierten SQL-Abfrage aus. #Es gibt keinen Verbindungspool, was nützen Sie?

Verwandte Empfehlungen:

Fragen zu gleichzeitigen MySQL-Abfragen

Das obige ist der detaillierte Inhalt vonSo fragen Sie MySQL gleichzeitig mit PHP ab. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn