web-dev-qa-db-fra.com

Comment définir un temps d'exécution maximum pour une requête mysql?

Je voudrais définir un temps d'exécution maximum pour les requêtes SQL comme set_time_limit () en php. Comment puis-je faire ?

20
microry

Je pensais que ça faisait un peu plus longtemps, mais selon ceci

MySQL 5.7.4 permet de définir des délais d’exécution côté serveur, spécifiés en millisecondes, pour les instructions SELECT en lecture seule de niveau supérieur.

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

Notez que cela ne fonctionne que pour les instructions SELECT en lecture seule.

Update: Cette variable a été ajoutée à MySQL 5.7.4 et renommée max_execution_time dans MySQL 5.7.8. ( la source )

20
Westy92

Si vous utilisez le pilote natif mysql (commun depuis php 5.3) et l'extension mysqli , vous pouvez le faire avec une requête asynchrone:

<?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());
}

Les drapeaux que je donne à mysqli_query accomplissent des tâches importantes. Il indique au pilote client d'activer le mode asynchrone, tout en nous obligeant à utiliser un code plus détaillé, mais nous permet d'utiliser un délai d'attente (et d'émettre des requêtes simultanées si vous le souhaitez!). L'autre indicateur indique au client de ne pas mettre en mémoire tampon la totalité du jeu de résultats. 

Par défaut, php configure ses bibliothèques client mysql pour extraire en mémoire l'ensemble des résultats de votre requête avant que votre code php ne commence à accéder aux lignes du résultat. Cela peut prendre beaucoup de temps pour transférer un résultat volumineux. Nous le désactivons, sinon nous risquons de perdre du temps en attendant la fin de la mise en mémoire tampon.

Notez qu'il y a deux endroits où nous devons vérifier le dépassement d'une limite de temps: 

  • L'exécution réelle de la requête
  • en récupérant les résultats (données)

Vous pouvez accomplir pareil dans le PDO et l’extension mysql classique. Ils ne prennent pas en charge les requêtes asynchrones. Vous ne pouvez donc pas définir de délai d'attente au moment de l'exécution de la requête. Cependant, ils prennent en charge les ensembles de résultats non mis en mémoire tampon et vous pouvez donc au moins implémenter un délai d'attente pour l'extraction des données.

Pour de nombreuses requêtes, mysql est capable de commencer à diffuser les résultats presque immédiatement, et les requêtes non mises en mémoire tampon vous permettront donc de mettre en œuvre de manière assez efficace les délais d'attente pour certaines requêtes. Par exemple, un 

select * from tbl_with_1billion_rows

peut commencer à diffuser des lignes immédiatement, mais 

select sum(foo) from tbl_with_1billion_rows

doit traiter l’ensemble de la table avant qu’elle ne puisse vous renvoyer la première ligne. Dans ce dernier cas, le délai d’expiration d’une requête asynchrone vous épargnera. Cela vous épargnera également de vieilles impasses et d’autres choses.

ps - Je n'ai inclus aucune logique de temporisation sur la connexion elle-même.

8
goat

Vous pouvez trouver la réponse sur cet autre S.O. question:

MySQL - puis-je limiter le temps maximal alloué à l'exécution d'une requête?

un travail cron qui s'exécute toutes les secondes sur votre serveur de base de données, se connectant et effectuant les opérations suivantes:

  • AFFICHER LA LISTE DE PROCESSUS
  • Trouvez toutes les connexions dont le temps d'interrogation est supérieur au temps maximal souhaité.
  • Exécutez KILL [id de processus] pour chacun de ces processus
4
Rafa

pt_kill a une option pour ce type. Mais il s’agit d’une demande et non d’une surveillance continue. Il fait ce que @Rafa a suggéré. Cependant, voir --sentinel pour un indice sur la façon de s’approcher de cron.

0
Rick James