8
votes

peupler une mysql avec une grande série de rangées rapidement

J'ai une table mysql qui ressemble à ceci:

Table MySQL: Statut

La SQL pour créer la structure est la suivante: xxx

Il stocke un ID unique , Respectecode , et < Code> LastUpdate . Le responsable est un code de réponse HTTP: 404, 500, 503, 200, etc.

J'ai une URL pour correspondre à chaque ID pour Ce que je fais une demande HTTP et enregistrer dans ce tableau l'heure que j'ai apportée la demande et la réponse reçue.

Le script fait cette requête sur le statut Tableau: xxx

xxxx serait une date où je décide que quelque chose de plus âgé que cette date ne doit être rafraîchie quel que soit le code de réponse. En outre, je souhaite remédier à la demande HTTP si je n'ai pas reçu de 200 ou 404 quel que soit le dernier lastUpdate date. I limite à 100 parce que je ne fonctionne que 100 à la fois, puis je l'ai dormi pendant un certain temps et que je le fais plus 100 plus tard, et ainsi de suite.

Quoi qu'il en soit, tout ce qui est Bien, mais ce que je veux faire, c'est peupler la table à l'avance avec dire une série comme celle-ci: xxx

avis, seul l'ID est incrémenté, mais ce n'est pas nécessairement Commencez à 1 pour mes besoins. Je veux que la table pré-peuplée comme ceci, car alors la requête ci-dessus peut continuer à saisir ID est pour ceux que nous devons être recouverts, et je voudrais ne pas avoir à insérer quelque chose de plus dans la Status TABLE AS L'ID S est fini et ne changera pas (mais il y en a beaucoup).

J'ai essayé d'utiliser Java, (bien que Php, c # ou quoi que ce soit le même concept et que je ne compte pas pour moi quelle langue j'utilise ici): xxx

Ceci commence les inserts, mais le problème est que Il faut une quantité de temps extraordinaire pour peupler la table (je n'ai pas de temps exact, mais c'était couru pendant des heures). Donc, ma question se résume à: Y a-t-il un moyen simple et efficace de remplir une table MySQL avec une masse de rangées comme celle-ci?


2 commentaires

Ajout d'une solution pure SQL à ma réponse, faites-moi savoir si vous trouvez quelque chose plus rapide.


Dupliqué possible de Comment insérer 20 millions d'enregistrements dans la base de données MySQL aussi vite que possible .


4 Réponses :


1
votes

Vous créez une grande déclaration par lots à effectuer. Essayez de le diviser en petits paquets en utilisant, par exemple. Appelez ExecuteBatch () Tous les 1000 incréments de I (à l'aide de MOD (I) Yaddayadda) à l'intérieur de la boucle. Cela devrait accélérer le processus: xxx


1 commentaires

J'ai remarqué que l'exécution du lot (comme dans ma question) remplit toujours la table activement (par exemple, je peux regarder le remplissage de DB) comme votre extrait ici. Cependant, je n'aiffectueusement aucune différence majeure dans la performance des inserts.



9
votes

Que diriez-vous de paramètres auto_incrènement code> sur la clé primaire.

Ensuite, insérez les centaines de cent (ou mille) de la manière dont vous aimez (votre exemple ou l'exemple de Docjones vous a donné). P >

Ensuite, utilisez P>

INSERT INTO table SELECT NULL, '503', NOW() FROM table AS t1 CROSS JOIN table t2;


2 commentaires

Je pense que cette idée est vraiment désireuse. Je vais essayer cela.


Attention avec le croix rejoindre Vous pouvez entrer 10 valeurs manuellement puis exécuter croix jointure et obtenir 10 + 10 ^ 2 = 110, puis vous répéterez la joindre et POOF Vous avez 110 + 110 ^ 2 = 12.210, à la troisième répétition, vous avez déjà 149 096 310 - cent quarante neuf millions d'entrées , qui chowleront sur certains Disk-io - et prenez le temps d'écrire un peu de temps.



14
votes

En règle générale, vous pouvez utiliser un ou plusieurs des éléments suivants:

  • Démarrez une transaction, faites des insertions, commettez li>
  • Pack Plusieurs valeurs dans un seul insert dans la requête LI>
  • déposez toutes les contraintes avant de faire une insertion et de rétablir des contraintes après l'insertion de masse (à l'exception de la clé primaire, pas très sûre à ce sujet) LI>
  • Utilisez insérer dans ... Sélectionnez CODE> si approprié li> ul>

    la première (utiliser des transactions) est le plus susceptible d'aider, mais je ne suis pas sûr que cela fonctionne sur des tables myisam, avec Innodb, il fait un très bon travail - je n'utilise que ceux quand je suis forcé Pour utiliser MySQL, je préfère PostgreSQL. P>

    Dans votre cas spécifique, insérez 100 000 lignes de données, vous pouvez effectuer les éléments suivants: P>

    Query OK, 100000 rows affected (0.70 sec)
    Records: 100000  Duplicates: 0  Warnings: 0
    


7 commentaires

Si vous exécutez de nombreuses instructions inserves, le regrouper dans des transactions empêche la DB de l'écriture sur le disque après chacune, elle garantit qu'ils se sont engagés à être déterminés à la fois à la fin de la transaction.


Cela semble assez rapide, pouvez-vous expliquer brièvement ce qui se passe dans cette requête?


Je crée des numéros consécutifs, en joignant 5 tables contenant 0 à 9, puis sélectionnez le numéro, la constante, la constante ... ce qui est très rapide ... puis insérez toutes les entrées 100 000 dans une seule transaction puisqu'il s'agit d'une seule requête.


Oh, pourriez-vous s'il vous plaît cocher la réponse car cela fonctionne et je ne pense pas que cela puisse être fait plus vite que cela (du moins pas dans MySQL), cependant, si quelqu'un propose une solution plus rapide plus tard, vous pouvez simplement marquer cela comme le bonne réponse à la place.


@ user17753 J'ai écrit un équivalent postgreSQL pour cette énorme sélection, espérons-le, il sera plus facile de comprendre ce que je faisais sqlfiddle.com/#!1/d41d8/501 ... Je l'ai écrit seulement jusqu'à 20 000 au lieu de 100 000 parce que je ne voulais pas trop surcharger les serveurs Sqlfiddle trop


Solution parfaite pour dupliquer les lignes lorsque les données sont exactement les mêmes. Avant que l'insert ne prend 20s chaque 10000 rangées. Maintenant 1s. Vraiment parfait.


Tout simplement génial ;)



2
votes

solution PHP pour les charger par lots de 100:

for ($i = 0; $i < 100000; $i+=100) {
  $vals = implode(', ', 
                  array_map(function($j) { return "($j, default, default)";},
                            range($i, $i+100)));
  mysqli_query($dbh, 'insert into status values ' . $vals) or die mysqli_error($dbh);
}


0 commentaires