Heim  >  Artikel  >  Datenbank  >  Streaming-Abfrage- und Cursor-Abfragemethoden in MySQL (Zusammenfassungsfreigabe)

Streaming-Abfrage- und Cursor-Abfragemethoden in MySQL (Zusammenfassungsfreigabe)

WBOY
WBOYnach vorne
2022-08-17 18:08:304107Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über MySQL. Er stellt hauptsächlich die Streaming-Abfrage- und Cursor-Abfragemethoden in MySQL vor. Er hat einen guten Referenzwert und ich hoffe, dass er für alle hilfreich ist.

Streaming-Abfrage- und Cursor-Abfragemethoden in MySQL (Zusammenfassungsfreigabe)

Empfohlenes Lernen: MySQL-Video-Tutorial

1. Geschäftsszenario

Jetzt muss das Geschäftssystem 5 Millionen Datenzeilen aus der MySQL-Datenbank zur Verarbeitung lesen

  • Daten migrieren
  • Daten exportieren
  • Batch Verarbeitung von Daten

Zweitens: Listen Sie die drei Verarbeitungsmethoden auf

  • Regelmäßige Abfrage: 5 Millionen Daten gleichzeitig in den JVM-Speicher einlesen oder Seiten einlesen
  • Streaming-Abfrage: Stück für Stück lesen und in die JVM laden Speicher für die Geschäftsverarbeitung
  • Cursorabfrage: Wie beim Streaming wird durch den fetchSize-Parameter gesteuert, wie viele Daten gleichzeitig gelesen werden.

2.1 Reguläre Abfrage

Standardmäßig wird der vollständige Abrufergebnissatz gespeichert Erinnerung. In den meisten Fällen ist dies die effizienteste Vorgehensweise und einfacher umzusetzen.

Angenommen, eine einzelne Tabelle hat ein Datenvolumen von 5 Millionen, niemand wird sie sofort in den Speicher laden und im Allgemeinen wird Paging verwendet.

Hier dient die Testdemo nur der Überwachung der JVM, daher wird kein Paging verwendet und die Daten werden auf einmal in den Speicher geladen

Der gesamte Abfrageprozess erhöht die Heap-Speichernutzung allmählich und führt schließlich zu OOM:

java.lang.OutOfMemoryError: GC-Overhead-Limit überschritten

1. GC wird häufig ausgelöst

2 Es gibt versteckte OOM-Gefahren

2.2 Streaming-Abfrage

Eine Sache, die Sie bei Streaming-Abfragen beachten sollten: Alle Zeilen im Ergebnissatz müssen gelesen (oder geschlossen) werden, bevor andere Abfragen für die Verbindung ausgegeben werden können, andernfalls wird eine Ausnahme ausgelöst und die entsprechende Abfrage ausgelöst wird die Verbindung monopolisieren.

Den Testergebnissen nach zu urteilen, hat die Streaming-Abfrage die Abfragegeschwindigkeit nicht verbessert

@Test
public void generalQuery() throws Exception {
    // 1核2G:查询一百条记录:47ms
    // 1核2G:查询一千条记录:2050 ms
    // 1核2G:查询一万条记录:26589 ms
    // 1核2G:查询五万条记录:135966 ms
    String sql = "select * from wh_b_inventory limit 10000";
    ps = conn.prepareStatement(sql);
    ResultSet rs = ps.executeQuery(sql);
    int count = 0;
    while (rs.next()) {
        count++;
    }
    System.out.println(count);
}

JVM-Überwachung

Wir haben den Heap-Speicher reduziert - ist nicht passiert OOM

2.3 Cursorabfrage

Hinweis:

1. Parameter müssen in den Datenbankverbindungsinformationen gespleißt werden

useCursorFetch=true

2. Zweitens legen Sie die Anzahl der von der Anweisung gelesenen Daten fest B. 1000 auf einmal

Den Testergebnissen nach zu urteilen, hat die Cursorabfrage die Abfragegeschwindigkeit bis zu einem gewissen Grad verkürzt

@Test
public void streamQuery() throws Exception {
    // 1核2G:查询一百条记录:138ms
    // 1核2G:查询一千条记录:2304 ms
    // 1核2G:查询一万条记录:26536 ms
    // 1核2G:查询五万条记录:135931 ms
    String sql = "select * from wh_b_inventory limit 50000";
    statement = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
    statement.setFetchSize(Integer.MIN_VALUE);
    ResultSet rs = statement.executeQuery(sql);
    int count = 0;
    while (rs.next()) {
        count++;
    }
    System.out.println(count);
}

JVM-Überwachung

Wir haben den Heapspeicher reduziert -Xms70m -Xmx70m

Das haben wir festgestellt In einem Single-Thread-Fall können Cursorabfragen wie Streaming-Abfragen sehr gut vermieden werden, OOM zu vermeiden, und Cursorabfragen können die Abfragegeschwindigkeit optimieren.

3. RowData

ResultSet.next() Die Logik besteht darin, die Klasse ResultSetImpl zu implementieren, um jedes Mal die nächste Datenzeile von RowData abzurufen. RowData ist eine Schnittstelle und das Implementierungsbeziehungsdiagramm lautet wie folgt: 3.1 RowDataStatic: Standardmäßig verwendet ResultSet die RowDataStatic-Instanz. Wenn das RowDataStatic-Objekt generiert wird, werden alle Datensätze im ResultSet in den Speicher eingelesen. und dann durch next() geleitet. Eins nach dem anderen aus dem Speicher lesen

3.2 RowDataDynamic

Wenn Streaming-Verarbeitung verwendet wird, verwendet ResultSet das RowDataDynamic-Objekt, und dieses Objekt initiiert IO, um jedes Mal, wenn next() ist, eine einzelne Datenzeile zu lesen aufgerufen


3.3 RowDataCursor

RowDataCursor Der Aufruf ist eine Stapelverarbeitung, und dann wird das interne Caching durchgeführt. Der Prozess ist wie folgt:

Zunächst wird überprüft, ob sich Daten in seinem eigenen internen Puffer befinden, die nicht zurückgegeben wurden. Wenn dies der Fall ist, wird zur nächsten Zeile zurückgekehrt.

Wenn der gesamte Lesevorgang abgeschlossen ist, wird eine neue Anforderung zum Lesen des fetchSize-Mengenergebnisses ausgelöst

und das Rückgabeergebnis im internen Puffer speichern und dann zurückkehren die erste Datenzeile

Zusammenfassung:

Der standardmäßige RowDataStatic liest alle Daten in den Client-Speicher, es ist auch unsere JVM;

RowDataDynamic liest ein Datenelement pro IO-Aufruf;

RowDataCursor liest fetchSize-Zeilen nacheinander und initiiert dann einen Anforderungsaufruf, nachdem der Verbrauch abgeschlossen ist.
  • 4. JDBC-Kommunikationsprinzip
  • Die Interaktion zwischen JDBC und dem MySQL-Server erfolgt über Socket. Entsprechend der Netzwerkprogrammierung kann MySQL als SocketServer betrachtet werden, daher sollte ein vollständiger Anforderungslink sein:
  • JDBC-Client –> Client-Socket –> MySQL-Kernel-Socket-Puffer –> Eine gewöhnliche Abfrage lädt alle abgefragten Daten in die JVM und verarbeitet sie dann.

    Wenn die Menge der Abfragedaten zu groß ist, kommt es weiterhin zu GC und dann kommt es zu einem Speicherüberlauf

    4.2 streamQuery-Streaming-Abfrage

    Wenn der Server bereit ist, von den ersten Daten zurückzukehren, wird er geladen Die Daten werden in den Puffer übertragen und die TCP-Verbindung wird in den Kernel-Puffer des Client-Computers eingefügt. Die Methode inputStream.read() von JDBC wird aktiviert, um die Daten zu lesen Wenn es aktiviert ist, liest es jedes Mal nur Daten einer Paketgröße und gibt nur eine Datenzeile zurück. Wenn ein Paket eine Datenzeile nicht zusammenstellen kann, wird ein anderes Paket gelesen.

    4.3 CursorQuery Cursor-Abfrage

    Wenn der Cursor aktiviert ist und der Server Daten zurückgibt, gibt er Daten entsprechend der Größe von fetchSize zurück, und wenn der Client Daten empfängt, liest er jedes Mal alle Pufferdaten. Wenn die Daten 100 Millionen Daten umfassen und FetchSize auf 1000 eingestellt ist, werden 100.000 Roundtrip-Kommunikationen durchgeführt.

    Da MySQL nicht weiß, wann der Client die Daten verbraucht hat, verfügt seine eigene entsprechende Tabelle möglicherweise über eine DML-Schreiboperation. Zu diesem Zeitpunkt muss MySQL einen temporären Speicherplatz erstellen, um die Daten zu speichern, die entfernt werden müssen.

    Wenn Sie also useCursorFetch zum Lesen einer großen Tabelle aktivieren, werden Sie bei MySQL mehrere Phänomene beobachten:

    1. IOPS steigt

    2. Speicherplatz steigt

      3. Nachdem der Client-JDBC SQL initiiert, dauert es lange Warten auf die SQL-Antwortdaten
    • 4 Nachdem die Datenvorbereitung abgeschlossen ist und die Datenübertragung beginnt, beginnt die Netzwerkantwort zu steigen und die IOPS wechselt von „Lesen und Schreiben“. "lesen".
    • IOPS (Eingabe/Ausgabe pro Sekunde): Die Anzahl der Lese- und Schreibvorgänge auf der Festplatte
    • 5. CPU und Speicher erhöhen sich um einen bestimmten Anteil
    • 5. Parallelitätsszenarien
    • Gleichzeitige Aufrufe: Jmete 10 Threads gleichzeitig 1 Sekunde Der Speicherleistungsbericht für den Aufruf von
    Stream-Abfrage lautet wie folgt: Gleichzeitige Aufrufe wirken sich ebenfalls sehr gut auf die Speichernutzung aus, und es gibt keine Überlagerungserhöhung. Der Speicherleistungsbericht für die Cursorabfrage lautet wie folgt: 1 Sekunde

    6. Zusammenfassung

    1. Sowohl die Cursorabfrage als auch die Streaming-Abfrage können OOM in einem einzelnen Thread vermeiden.

    2 mit gewöhnlicher Abfrage;

    3. In gleichzeitigen Szenarien ist der Trend des Streaming-Abfrage-Heapspeichers stabiler und es gibt keinen additiven Anstieg.

    Empfohlenes Lernen:

    MySQL-Video-Tutorial

Das obige ist der detaillierte Inhalt vonStreaming-Abfrage- und Cursor-Abfragemethoden in MySQL (Zusammenfassungsfreigabe). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:jb51.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen