2011-01-28 4 views
2

J'ai un processus qui lit une ligne de données ligne par ligne, analyse et insère les données dans une table MyISAM. Au premier démarrage, ça va très vite, probablement autour de 1000 enregistrements par seconde. Au fur et à mesure que le temps avance, il devient de plus en plus lent. En ce moment, nous sommes à environ 1 rangs toutes les 180 secondes.Requête dans une boucle de plus en plus lente

La syntaxe générale de la fonction est la suivante:

function parse($file) { 
    $handle = fopen($file, 'r'); 
    while (!feof($handle)) { 
    $line = fgets($fileHandle, 1000); 
    switch (substr($line, 0, 2)) { //gets record type 
     case '01' : 
     //parse the record 
     //escapes some strings with mysql_real_escape_string() 
     mysql_query('INSERT INTO table VALUES ($a, $b, $c...'); 
     case '02' : 
     ... 
    } 
    } 
} 

Le fichier en cours a analysé quelques millions d'enregistrements. Le serveur ne semble pas perdre d'espace mémoire. Est-ce que quelqu'un sait ce qui pourrait ralentir le processus?

+0

Y a-t-il un index sur la table? La mise à jour de l'index pourrait être le coupable. Aussi, à quelle fréquence vous engagez-vous? –

+0

Avez-vous une indexation sur 'table'? – bensiu

+1

@bensiu & @Jim Garrison - Pourquoi auriez-vous besoin d'indexation pour INSERT? – FeRtoll

Répondre

6

Cela a probablement à voir avec l'écriture fréquente de vos index. Vous utilisez déjà MyISAM, ce qui serait ma première suggestion.

Quelques suggestions

  1. Lot insérer 100 lignes
  2. Utilisez INSERT DELAYED permettre à MySQL pour permettre inserts de terminer rapidement faire la queue, et MySQL insère le disque lorsque les ressources sont plus le permettent.
  3. script pour créer un dump SQL/fichier délimité que vous pouvez charger en utilisant dans le fichier des fonctions d'importation, voir http://dev.mysql.com/doc/refman/5.1/en/load-data.html qui sera beaucoup plus rapide que les inserts de traitement par lots
+0

Merci, je vais essayer ceux-ci. Il n'y a qu'un seul index, une clé primaire sur une colonne d'incrémentation automatique. –

+0

@ParrisVarney - Le 'INSERT' que vous avez donné n'est pas compatible avec un' AUTO_INCREMENT'! S'il vous plaît fournir 'SHOW CREATE TABLE'. –

1

Je pense que vous devriez exécuter des requêtes dans la transaction (il a accéléré), préférable d'utiliser PDO parce que c'est beaucoup plus sûr. Les instructions préparées dans PDO vont probablement être plus rapides, mais au moins plus sûres car elles sont invulnérables aux injections SQL. Cela va être beaucoup plus rapide. J'ai un exemple prêt avec des étiquettes pour vous:

<?php 

$array = array(
    "ActionScript", 
    "AppleScript", 
    "Asp", 
    "BASIC", 
    "C", 
    "C++", 
    "Clojure", 
    "COBOL", 
    "ColdFusion", 
    "Erlang", 
    "Fortran", 
    "Groovy", 
    "Haskell", 
    "Java", 
    "JavaScript", 
    "Lisp", 
    "Perl", 
    "PHP", 
    "Python", 
    "Ruby", 
    "Scala", 
    "Scheme" 
); 

function createTable($db) { 
    $db->exec("CREATE TABLE IF NOT EXISTS tags (id INTEGER PRIMARY KEY, tag TEXT NOT NULL UNIQUE)"); 
} 

function insertData($db, $array) { 
    $db->beginTransaction(); 

    foreach($array as $elm) { 
     try { 
      $placeholder = array($elm); 
      $stmt = $db->prepare("INSERT INTO tags (tag) VALUES (?)"); 
      $stmt->execute($placeholder); 
     } catch(PDOException $e) { 
      /*** roll back the transaction if we fail ***/ 
      $db->rollback(); 
      /*** echo the sql statement and error message ***/ 
      echo $sql . '<br />' . $e->getMessage(); 
     } 
    } 

    $db->commit(); 
} 

$db = new PDO('sqlite:database/tags.sqlite3'); 
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); 
// 
createTable($db); 
insertData($db, $array); 

P.S: Je voudrais également souligner que InnoDB va probablement être mieux.

+0

MyISAM ignore totalement les transactions. –

+0

je ne savais pas ça! – Alfred

+0

Les données proviennent d'un flux interne, je ne suis pas inquiet pour les injections SQL. Je ne pense pas que la version de Php que j'utilise supporte PDO, mais cela pourrait ajouter des munitions à mon cas pour mettre à jour. Est-ce qu'il fait des optimisations que MySQL ne fait pas déjà? –

3

Vous avez probablement au moins un indice sur ce tableau. Chaque rangée est donc insérée dans un index de plus en plus grand. Avant de commencer votre charge, faire

ALTER TABLE TABLE DISABLE KEYS

Une fois que vous avez terminé faire

ALTER TABLE TABLE ENABLE CLÉS

Réactiver les clés peuvent prendre un certain temps. N'essayez pas d'utiliser la table pendant que vous la chargez. En outre, INSERT DELAYED peut aider. Mais probablement pas si vous faites cette table charge sur un serveur de base de données par ailleurs calme.

Questions connexes