11
votes

Pourquoi MySQL 'insert-il dans ... Sélectionnez ...' tellement plus lentement qu'un simple choix?

J'essaie de stocker un résultat de la requête dans une table temporaire pour un traitement ultérieur.

id  select_type     table       type    possible_keys   key     key_len ref                 rows        Extra
1   PRIMARY         <subquery3> ALL     \N              \N      \N      \N                  \N          \N
1   PRIMARY         foo         ref     PRIMARY         PRIMARY 3       <subquery3>.fooId   9747434     Using where
2   SUBQUERY        someTable   range   PRIMARY         PRIMARY 3       \N                  136933000   Using where with pushed condition; Using MRR; Using temporary; Using filesort
3   MATERIALIZED    tmpBar      ALL     \N              \N      \N      \N                  1000        \N


5 commentaires

Vous devriez être plus précis et fournir des données que vous écrivez. Aussi insérer .. Sélectionnez la syntaxe DIFFÉRENTE. Votre échantillon entraînera une erreur.


bonne question. Je ne sais pas vraiment comment MySQL se réserve mémoire pour elle-même. Si cela passe par l'API OS, il pourrait simplement Demande pour la mémoire, qui serait ensuite servi comme RAM ou HardDrive espace, selon Statut du système. Voir la gestion des octets virtuels de Windows.


Avez-vous essayé un Create Table ... Sélectionnez la requête -TYPE pour la comparaison? dev.mysql.com/doc/refman/5.0/ FR / CREATE-TABLE-SELECT.HTML


@Aladomundo: Pourquoi dites-vous que ma syntaxe est fausse? Je n'ai aucune erreur.


@Xiankai: J'ai fait :( le même résultat que l'insertion dans ... Sélectionnez


3 Réponses :


0
votes

La raison en laquelle l'ordinateur lit et écrit et la façon dont un fichier temporaire fonctionne. Sélectionner est la lecture de données dans un fichier indexé sur le disque dur, tandis que l'insertion utilise un fichier temporaire et écrit dans ce fichier. Plus de bélier est nécessaire et le faire est plus difficile. Quant pourquoi il faut une minute, je ne suis pas sûr, mais je pense que le code pourrait être un peu incorrect afin de contribuer.


2 commentaires

Ma table temporaire a son moteur explicitement défini sur la "mémoire". Cela ne signifie-t-il pas qu'il devrait rester en RAM? Ma machine a 32 Go de RAM dont 39% sont utilisées. Et ma table temporaire a seulement 1000 rangées ...


Avez-vous déjà eu une réponse à cela? Ou comprendre comment améliorer la performance? Je reçois le même comportement, où le Select prend la sous-seconde, mais l'insert prend 30 secondes. C'est complètement déroutant. Je me demande si c'est un bug? Pour contourner cela, j'ai essayé de créer un curseur sur les données que je sélectionnais et inséré une ligne à la fois et que c'était plus rapide. Qui est fou. Je vais essayer une question similaire à la vôtre, mais il semble qu'il n'y ait aucune réponse à cela.



3
votes

J'ai écrit un commentaire ci-dessus, puis tomba à travers cela comme une solution de contournement.

Cela accomplira ce que vous voulez faire. P>

SELECT * FROM aTable INTO OUTFILE '/tmp/atable.txt';
LOAD DATA INFILE '/tmp/atable.txt' INTO TABLE anotherTable;


0 commentaires

1
votes

J'exécute le même problème et je jouais avec des sous-coutumes qui l'ont résolu. Si le SELECT a une énorme quantité de lignes, sa prise de manière très longue pour insérer les données. Exemple:

INSERT INTO b2b_customers (b2b_name, b2b_address, b2b_language)
SELECT * FROM (
SELECT customer_name, customer_address, customer_language
FROM customers
WHERE customer_name LIKE "%john%"
ORDER BY customer_created_date DESC
LIMIT 1
) sub1


6 commentaires

Vous n'êtes pas sûr de savoir pourquoi il faut un milliseconde sur Lire les données à 60 secondes à écrire 1000 enregistrements? Peut-être parce que la lecture est plus rapide que d'écrire?


Oui, c'est vrai, mais je n'écris que 1 ligne tout en utilisant la limite 1.


Où Customer_Name aime "% John%" - Il s'agit d'une numérisation de table complète. Une fois que chaque enregistrement est numérisé et réduit pour récupérer ce qui contient john . Cela prend un moment. Ensuite, vous écrivez 1 disque. C'est inefficace.


Donc, MySQL écrit toutes les données dans une table temporaire et, à la fin, il reconnaît que je mets une limite 1 et n'écrit que le premier enregistrement dans la table? Cela expliquerait également pourquoi ma capsulation avec la sous-requête serait beaucoup plus rapide.


Il tamponne les enregistrements qu'il a trouvés (nous pouvons dire qu'il écrit à la table Temp, oui), puis il n'utilise qu'un seul enregistrement, correct.


Les résultats du SELECT sont mis en mémoire tampon. Donc, aucun des enregistrements n'est inséré tant que le Sélectionnez Terminé.