1. #1
    Membre confirmé

    Profil pro
    Inscrit en
    septembre 2004
    Messages
    480
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2004
    Messages : 480
    Points : 494
    Points
    494

    Par défaut Insertion de masse sans interruption

    Bonjour.

    Je souhaite insérer les données d'une table dans une autre en "zappant" les erreurs, c'est-à-àdire que si une ligne est déjà présente dans la table cible (selon la clé primaire), elle est ignorée et l'insertion continue.

    Je ne souhaite pas faire d'insertion ligne à ligne car il s'agit de gros volumes (table source 3 millions, table cible 45 millions). Je souhaite simplement faire un "insert into... select * from... " (les deux tables ont la même structure) en ignorant les erreurs. L'insertion est dans une fonction PL/SQL mais je ne veux pas de curseurs ou autre sous peine de performances dégradées (il me semble).

    Est-ce possible à l'aide d'options (que j'ignore) ?

    Merci

  2. #2
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Ingénieur d'études décisionnel
    Inscrit en
    mai 2002
    Messages
    7 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur d'études décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 7 251
    Points : 22 079
    Points
    22 079

    Par défaut

    Quelque chose comme ça :
    INSERT INTO table_cible
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT  *
    FROM    table_source  src
    WHERE   NOT EXISTS
            (   SELECT  NULL
                FROM    table_cible cbl
                WHERE   cbl.id_table  = src.id_table
            )
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    INSERT INTO table_cible
    SELECT  *
    FROM    (   SELECT  *
                FROM    table_source  src
            MINUS
                SELECT  *
                FROM    table_cible   cbl
            )
    Si tu veux aussi faire des mises à jour, regarde du côté de la commande MERGE.
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  3. #3
    Membre confirmé

    Profil pro
    Inscrit en
    septembre 2004
    Messages
    480
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2004
    Messages : 480
    Points : 494
    Points
    494

    Par défaut

    Merci al1_24.

    J'avais pensé à quelque chose comme la première solution mais ça ne me semblait pas très performant. En fait, j'ai testé un DELETE WHERE EXISTS sur la table source avant d'insérer, mais du coup il compare ligne à ligne (les PK). Je voulais voir s'il n'y avait pas une autre façon de faire en occultant volontairement les erreurs.

    Pour la seconde, je crois que le minus élimine les lignes exactement similaires et non seulement sur la clé primaire. Elle ne conviendra pas.

  4. #4
    Membre actif
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    mai 2012
    Messages
    109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : mai 2012
    Messages : 109
    Points : 294
    Points
    294

    Par défaut

    Bonjour,

    Une autre solution est d'ajouter à votre ordre INSERT le hint /*+ IGNORE_ROW_ON_DUPKEY_INDEX(<nom_de_la_table>, <nom_de_l'index>)*/

    Mais je ne saurais trop vous conseiller de faire un MERGE en bonne et due forme : j'ai découvert l'existence de ce hint sur un billet de blog où l'on expliquait les problèmes de performance en cas d'un grand nombre de valeurs invalides.

  5. #5
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Ingénieur d'études décisionnel
    Inscrit en
    mai 2002
    Messages
    7 251
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur d'études décisionnel
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 7 251
    Points : 22 079
    Points
    22 079

    Par défaut

    Citation Envoyé par GoLDoZ Voir le message
    Pour la seconde, je crois que le minus élimine les lignes exactement similaires et non seulement sur la clé primaire. Elle ne conviendra pas.
    Et que fais-tu alors des lignes de la source dont l'identifiant est déjà présent dans la cible mais dont les attributs sont différents ? Les modifications sont perdues ? La mise à jour est effectuée dans un autre traitement ?
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  6. #6
    Membre confirmé

    Profil pro
    Inscrit en
    septembre 2004
    Messages
    480
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2004
    Messages : 480
    Points : 494
    Points
    494

    Par défaut

    @Baldrick: merci pour l'info, je vais tester ça. Le MERGE ne m'intéresse pas car les doublons sont censés être exceptionnel et doivent être supprimés. Du coup, peut-être pas de problème de perf par rapport à ce que tu dis.

    @al1_24: les lignes supprimées ne sont pas censées arriver! C'est un patch pour faire le boulot que certains ne veulent pas faire... (je m'occupe d'un DWH et on n'est pas censé filtrer les données, sauf que régulièrement on a des fichiers pourris et il faut arbitrer. Dans le cas présent, ce sont des lignes qu'on a déjà reçues, et normalement un minus devrait suffire, mais j'ai standardisé les procédures et ça ne m'arrange pas).

  7. #7
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    octobre 2007
    Messages
    5 524
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : octobre 2007
    Messages : 5 524
    Points : 11 285
    Points
    11 285

    Par défaut

    Citation Envoyé par GoLDoZ Voir le message
    ...

    Je ne souhaite pas faire d'insertion ligne à ligne car il s'agit de gros volumes (table source 3 millions, table cible 45 millions). Je souhaite simplement faire un "insert into... select * from... " (les deux tables ont la même structure) en ignorant les erreurs. L'insertion est dans une fonction PL/SQL mais je ne veux pas de curseurs ou autre sous peine de performances dégradées (il me semble).

    Est-ce possible à l'aide d'options (que j'ignore) ?

    Merci
    D'abord en Oracle la notion de curseur est inhérente à toute requête SQL! En fait ce que vous voulez dire c'est un curseur au sens d'une structure de programmation propre au langage PL/SQL. Mais y compris dans ce cas c'est qui dégrade les performances ce n'est pas l'utilisation d'un curseur mais le traitement qui est conçu a travailler ligne à ligne au lieu de travailler en mode lot, c'est-à-dire ensemble des lignes.

    Les solutions que vous pouvez employer sont les suivantes:
    • en PL/SQL utilisez ForALL (travail par lot) avec la clause SAVE Exceptions
    • en SQL utilisez errror logging


    Une différence subtile existe entre les deux méthodes mais cela n'a pas d'importance dans notre discution.

    Mais dans tout les cases vous devez comprendre que la simple présence des anomalies et leur traitement, peu importe la méthode, va contribuer à allonger le temps de traitement d'une manière plutôt linéaire: plus de erreurs signifiant plus de temps de traitement.

    Si vos erreurs concernent uniquement des doublons alors vous pouvez envisager l'utilisation des solutions déjà proposées.

Discussions similaires

  1. [HIBERNATE] Problème d'insert de masse en HQL
    Par ange bleu dans le forum Hibernate
    Réponses: 9
    Dernier message: 20/04/2006, 09h39
  2. [Optimisation] Insert en masse
    Par bobic dans le forum Oracle
    Réponses: 1
    Dernier message: 14/12/2005, 21h11
  3. [9i] Insertion de masse
    Par sygale dans le forum SQL
    Réponses: 2
    Dernier message: 05/12/2005, 09h51
  4. [Optimisation] Insertion en masse !
    Par m-mas dans le forum MS SQL-Server
    Réponses: 1
    Dernier message: 26/10/2005, 16h40
  5. Réponses: 6
    Dernier message: 14/04/2004, 20h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo