it-swarm.com.de

Wie kann ich eine maximale Ausführungszeit für eine mysql-Abfrage festlegen?

Ich möchte eine maximale Ausführungszeit für SQL-Abfragen wie set_time_limit () in PHP festlegen. Wie kann ich ?

20
microry

Ich dachte, es ist schon etwas länger her, aber nach diesem

MySQL 5.7.4 bietet die Möglichkeit, serverseitige Ausführungszeitlimits (in Millisekunden) für SELECT-Anweisungen der obersten Ebene festzulegen, die nur Lesezugriff haben.

SELECT 
MAX_EXECUTION_TIME = 1000 --in milliseconds
* 
FROM table;

Beachten Sie, dass dies nur für schreibgeschützte SELECT-Anweisungen funktioniert.

Update: Diese Variable wurde in MySQL 5.7.4 hinzugefügt und in MySQL 5.7.8 in max_execution_time umbenannt. ( Quelle )

20
Westy92

Wenn Sie den systemeigenen mysql-Treiber (seit php 5.3 gemeinsam) und die Erweiterung mysqli verwenden, können Sie dies mit einer asynchronen Abfrage bewerkstelligen:

<?php

// Here's an example query that will take a long time to execute.
$sql = "
    select *
    from information_schema.tables t1
    join information_schema.tables t2
    join information_schema.tables t3
    join information_schema.tables t4
    join information_schema.tables t5
    join information_schema.tables t6
    join information_schema.tables t7
    join information_schema.tables t8
";

$mysqli = mysqli_connect('localhost', 'root', '');
$mysqli->query($sql, MYSQLI_ASYNC | MYSQLI_USE_RESULT);
$links = $errors = $reject = [];
$links[] = $mysqli;

// wait up to 1.5 seconds
$seconds = 1;
$microseconds = 500000;

$timeStart = microtime(true);

if (mysqli_poll($links, $errors, $reject, $seconds, $microseconds) > 0) {
    echo "query finished executing. now we start fetching the data rows over the network...\n";
    $result = $mysqli->reap_async_query();
    if ($result) {
        while ($row = $result->fetch_row()) {
            // print_r($row);
            if (microtime(true) - $timeStart > 1.5) {
                // we exceeded our time limit in the middle of fetching our result set.
                echo "timed out while fetching results\n";
                var_dump($mysqli->close());
                break;
            }
        }
    }
} else {
    echo "timed out while waiting for query to execute\n";
    var_dump($mysqli->close());
}

Die Flags, die ich an mysqli_query gebe, erledigen wichtige Dinge. Es weist den Client-Treiber an, den asynchronen Modus zu aktivieren, zwingt uns jedoch dazu, mehr ausführlichen Code zu verwenden, lässt uns jedoch ein Timeout verwenden (und auch gleichzeitige Abfragen ausführen, wenn Sie möchten!). Das andere Flag weist den Client an, die gesamte Ergebnismenge nicht im Arbeitsspeicher zwischenzuspeichern. 

Standardmäßig konfiguriert php seine mysql-Clientbibliotheken so, dass die gesamte Ergebnismenge Ihrer Abfrage in den Speicher geladen wird, bevor Ihr PHP-Code anfängt, auf Zeilen im Ergebnis zuzugreifen. Dies kann lange dauern, um ein großes Ergebnis zu übertragen. Wir deaktivieren ihn, andernfalls riskieren wir, dass es zu einer Zeitüberschreitung kommt, während auf die Pufferung gewartet wird.

Beachten Sie, dass es zwei Stellen gibt, an denen wir prüfen müssen, ob ein Zeitlimit überschritten wird: 

  • Die eigentliche Abfrageausführung
  • beim Abrufen der Ergebnisse (Daten)

Ähnliches können Sie in der PDO- und regulären MySQL-Erweiterung erreichen. Sie unterstützen keine asynchronen Abfragen. Daher können Sie für die Abfrageausführungszeit kein Timeout festlegen. Sie unterstützen jedoch ungepufferte Ergebnismengen, sodass Sie beim Abrufen der Daten mindestens ein Timeout implementieren können.

Bei vielen Abfragen kann mysql fast sofort mit dem Streaming der Ergebnisse beginnen. Ungepufferte Abfragen allein ermöglichen es Ihnen, Timeouts für bestimmte Abfragen etwas effektiv zu implementieren. Zum Beispiel a 

select * from tbl_with_1billion_rows

kann sofort mit dem Streaming von Zeilen beginnen, aber, 

select sum(foo) from tbl_with_1billion_rows

muss die gesamte Tabelle verarbeiten, bevor die erste Zeile an Sie zurückgegeben werden kann. In diesem letzteren Fall werden Sie durch das Timeout einer asynchronen Abfrage gerettet. Es wird dich auch vor einfachen alten Deadlocks und anderem Zeug retten.

ps - Ich habe keine Timeout-Logik für die Verbindung selbst eingefügt.

8
goat

Die Antwort finden Sie auf diesem anderen S.O. Frage:

MySQL - Kann ich die maximal zulässige Zeit für die Ausführung einer Abfrage begrenzen?

ein Cron-Job, der jede Sekunde auf Ihrem Datenbankserver ausgeführt wird, eine Verbindung herstellt und Folgendes ausführt:

  • PROZESSLISTE ANZEIGEN
  • Finden Sie alle Verbindungen mit einer Abfragezeit, die größer als Ihre maximal gewünschte Zeit ist
  • Führen Sie KILL [Prozess-ID] für jeden dieser Prozesse aus
4
Rafa

Bitte schreiben Sie Ihre Anfrage gerne um

select /*+ MAX_EXECUTION_TIME(1000) */ * from table

4
Manu Mohan T

pt_kill hat eine Option dafür. Aber es ist auf Abruf, nicht ständig überwacht. Es tut, was @Rafa vorschlug. In --sentinel finden Sie jedoch einen Hinweis, wie Sie mit cron näher kommen.

0
Rick James