web-dev-qa-db-fra.com

Sélectionnez Insert Insert dans ... Sélectionner

Au cours de mes recherches superficielles, je n'ai pas été en mesure de trouver une réponse définitive sur les avantages que SELECT INTO OUTFILE fournit sur INSERT INTO ... SELECT. En lisant le - docs en rapport avec INSERT INTO ... SELECT Concernant les serrures sur des tables InnoDB, il indique:

définit un enregistrement d'index exclusif sans verrouillage de l'espace indiqué dans chaque ligne insérée dans T. Si le niveau d'isolation de la transaction est lu engagé ou Innodb_Locks_unsafe_for_binlog est activé et le niveau d'isolation des transactions n'est pas sérialisable, Innodb effectue la recherche sur S comme une lecture cohérente (non serrures). Sinon, InnoDB sets des serrures suivantes partagées sur des rangées de S.

Pour éviter le verrou avec INSERT INTO ... SELECT Il semble que je dois assurer le niveau d'isolement est READ COMMITTED Pour éviter les verrous sur la table source pendant la requête.

Cependant, je n'ai pas pu trouver de réponse faisant autorité concernant les serrures et utiliser SELECT INTO OUTFILE, pas même les informations de verrouillage de référence MySQL DOCS .

Mon objectif est d'éviter de verrouiller la table source pendant que la requête fonctionne pour éviter l'empilement de connexion.

6
Mike Purcell

Vous devez utiliser Sélectionnez ... verrouillage en mode partage . Pourquoi ?

Sélectionnez ... verrouillage en mode Share définit un verrouillage en mode partagé sur toutes les lignes lues. D'autres sessions peuvent lire les lignes, mais ne peuvent pas les modifier avant que votre transaction s'engage. Si l'une de ces lignes a été modifiée par une autre transaction qui ne s'est pas encore engagée, votre requête attend que cette transaction se termine puis utilise les dernières valeurs.

Dans votre cas, vous pourriez essayer cela

START TRANSACTION;
SELECT ... LOCK IN SHARE MODE;
SELECT ... INTO OUTFILE;
ROLLBACK;

Cela ferait deux questions SELECT

  • Premier SELECT pour verrouiller les rangées dans la table que vous souhaitez
  • Deuxièmement SELECT pour effectuer SELECT ... INTO OUTFILE

Personnellement, je ne pense pas que vous deviez être ce lourd. L'isolement de la transaction doit être suffisamment intelligent pour retirer cet atomique SELECT et utiliser les mêmes lignes pour le INSERT. Je sais que j'ai dit should be C'est pourquoi vous vous posez la question en premier lieu.

Si vous faites SELECT ... INTO OUTFILE Comme une commande ou de la manière lourde, je propose que les données de la ligne de la table source seront entièrement lisibles.

donnez-lui un essai !!!

Mise à jour 2014-12-10 15:12 EST

Votre commentaire

Thx pour la réponse, et cela aide, mais le point principal de l'OP consistait à déterminer s'il y a un avantage pour l'utilisation de Sélectionner dans une insertion ... Sélectionnez-vous?

Ils sont de manière opérationnelle différente

  • SELECT INTO OUTFILE crée un fichier texte
  • INSERT INTO SELECT charge une table des résultats du SELECT

Mise à jour 2014-12-11 12:21 Est

La seule chose à laquelle je puisse penser dans ce contexte est le point à temps des données et lorsque vous l'utilisez. Avec les deux types d'opérations, il y aura du verrouillage partagé implicite.

Avec SELECT INTO OUTFILE, vous préparez un résultat et la sauvegarde de l'extérieur. Chargement de ces données dans une table à l'aide de LOAD DATA INFILE n'impliquera aucun verrouillage partagé pendant le processus de charge. Garde en tête que SELECT INTO OUTFILE va engager des E/S du disque et imposera toujours une certaine mise en cache en cours de route.

Avec INSERT INTO SELECT, les verrous partagés devront probablement vivre plus longtemps en InnoDB car vous verrouillez les lignes et utilisez ces mêmes lignes pour insérer dans une autre table.

Par conséquent, si je cherchais un bonus de performance, j'aurais donné le bord à INSERT INTO SELECT Parce que vous faites la même quantité de verrouillage partagée de ligne, les E/S du disque pour l'opération unique devraient être inférieurs à la SELECT INTO OUTFILE Et subséquente LOAD DATA INFILE. Bien sûr, vous devriez comparer les deux méthodes contre votre ensemble de données. Que pourrait être un bonus de performance pour un ensemble de données pourraient être un coût de performance pour un autre jeu de données?.

Mise à jour 2014-12-17 00:00 Est

Votre commentaire

Je n'ai pas été informé que vous avez mis à jour votre réponse, alors j'ai fait une prime en supposant que ce n'était pas le cas. Votre explication a du sens, en théorie, mais je recherche une réponse plus faisant autorité, dans l'espoir que les frais généraux du fichier séparé (comme vous l'avez correctement mentionné correctement) méritent de la complexité de l'amélioration des performances.

La seule réponse faisant autorité proviendrait de la documentation MySQL.

D'abord, qu'est-ce que la documentation MySQL charge de charge infilière dire?

La relevé d'infiltration de données de charge lit les lignes d'un fichier texte dans une table à une vitesse très élevée. Load Data Infile est le complément de sélectionner ... dans la tenue de service. (Voir la section 13.2.9.1, "Sélectionnez ... dans la syntaxe".) Pour écrire des données d'une table à un fichier, utilisez Sélectionner ... dans une tenue. Pour lire le fichier dans une table, utilisez l'infilure de données de charge.

Deux paragraphes plus tard , dit-il

Pour plus d'informations sur l'efficacité de l'insertion par rapport aux données de charge infini et accélère les données de charge en infiltration, reportez-vous à la section 8.2.2.1, "Vitesse des instructions d'insertion".

Lorsque vous regardez Vitesse des instructions d'insertion , il le dit:

Pour optimiser la vitesse d'insertion, combinez de nombreuses petites opérations en une seule grande opération. Idéalement, vous apportez une seule connexion, envoyez les données pour de nombreuses nouvelles lignes à la fois et retardez toutes les mises à jour de l'index et la vérification de la cohérence jusqu'à la fin.

Le temps nécessaire à l'insertion d'une ligne est déterminé par les facteurs suivants, où les chiffres indiquent des proportions approximatives:

Connexion: (3)

Envoi de requêtes au serveur: (2)

Analyse de la requête: (2)

Rangée d'insertion: (1 × taille de rangée)

Insertion d'index: (1 × Nombre d'index)

Fermeture: (1)

Cela ne prend pas en compte la surcharge initiale pour ouvrir des tables ouvertes, qui se fait une fois pour chaque requête en cours d'exécution.

La taille de la table ralentit l'insertion d'index par log n, en supposant des index b-arbres.

Vous pouvez utiliser les méthodes suivantes pour accélérer les inserts:

Si vous insérez de nombreuses lignes du même client en même temps, utilisez des instructions d'insertion avec plusieurs listes de valeurs pour insérer plusieurs lignes à la fois. Ceci est considérablement plus rapide (plusieurs fois plus vite dans certains cas) que d'utiliser des relevés d'insertion à une rangée séparés. Si vous ajoutez des données à une table non vide, vous pouvez régler la variable Bulk_Insert_Buffer_Size pour rendre l'insertion de données encore plus rapidement. Voir la section 5.1.4, "Variables du système de serveur".

Lors du chargement d'une table à partir d'un fichier texte, utilisez l'infilure de données de charge. Ceci est généralement 20 fois plus rapide que d'utiliser des déclarations insertiques. Voir la section 13.2.6, "Syntaxe d'infiltration de données de charge".

Profitez du fait que les colonnes ont des valeurs par défaut. Insertion des valeurs explicitement uniquement lorsque la valeur à insérer diffère de la valeur par défaut. Cela réduit l'analyse que MySQL doit faire et améliore la vitesse d'insertion.

Voir la section 8.5.4, "Chargement des données en vrac pour les tables d'innoDB" pour des conseils spécifiques aux tables InnoDB.

Reportez-vous à la section 8.6.2, "Chargement de données en vrac pour les tables de myisam" pour des conseils spécifiques aux tables de Myisam.

Les choses commencent à regarder un peu nébuleuse à ce stade car vous devez régler le processus de charge en termes de moteur de stockage. Myisam est plutôt directement en avant dans cette déclaration car Le tampon d'insertion en vrac est destiné à MyISAM uniquement et que les données de charge de la charge et que l'infilure des données de charge va exploiter la mémoire tampon d'insertion en vrac . InnoDB ne sera pas.

Jetez un coup d'œil à cette représentation picturale d'InnoDB (Percona CTO Vadim Tchachenko)

InnoDB Architecture

Il existe d'autres considérations pour modifier des options mais LOAD DATA INFILE _ va littéralement cheler tout dans le pool de tampons InnoDb, la mise en oeuvre des changements via la mémoire tampon de journal, la tampon d'écriture double, l'insertion de tampon (si la table cible dispose d'index nonuniques), redo journaux (ib_logfile0, ib_logfile1) et le fichier physique de la table. . C'est là que les avantages de l'infileur de données de charge doivent être annulés.

J'ai écrit à ce sujet

ÉPILOGUE

Comme je l'ai déjà dit dans ma mise à jour précédente à cette réponse

Par conséquent, si je cherchais un bonus de performance, j'aurais donné le bord à INSERT INTO SELECT Parce que vous faites la même quantité de verrouillage partagée de ligne, les E/S du disque pour l'opération unique devraient être inférieurs à la SELECT INTO OUTFILE Et subséquente LOAD DATA INFILE. Bien sûr, vous devriez comparer les deux méthodes contre votre ensemble de données. Que pourrait être un bonus de performance pour un ensemble de données pourraient être un coût de performance pour un autre jeu de données?.

Fondamentalement, vous devrez tester SELECT INTO OUTFILE/LOAD DATA INFILE contre INSERT INTO SELECT. Il peut être 6 d'une, une demi-douzaine de l'autre pour un ensemble de données et une victoire à la terre pour un autre jeu de données.

Tout étant dit de la MySQL Docs et de mes messages passés, je donne toujours le bord à INSERT INTO SELECT. Vous devrez simplement tester les deux méthodes.

5
RolandoMySQLDBA