IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes MySQL Discussion :

[Optimisation] Delete beaucoup plus lent que select


Sujet :

Requêtes MySQL

  1. #1
    Membre averti Avatar de GyZmoO
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2006
    Messages : 428
    Points : 301
    Points
    301
    Par défaut [Optimisation] Delete beaucoup plus lent que select
    Bonjour à tous !

    Nous avons un petit soucis que nous ne comprenons pas forcément.

    Je vous explique :

    Voici une table de notre base MySQL, contenant 70 000 000 de lignes dont la structure ressemble à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    MA_TABLE
    {
       PRI_ID         INTEGER NOT NULL,
       MY_DATE     TIMESTAMP NOT NULL,
       d'autres champs
    };
     
     
    ALTER TABLE MA_TABLE
           ADD  ( PRIMARY KEY (PRI_ID) ) ;
     
    ALTER TABLE MA_TABLE MODIFY COLUMN PRI_ID INTEGER NOT NULL AUTO_INCREMENT;
     
    CREATE INDEX MY_INDEX ON MA_TABLE
    (
           MY_DATE                      ASC
    );
    Bref, nous faisons une requête du style

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SELECT tous_mes_champs FROM MA_TABLE WHERE MY_DATE BETWEEN DATE1 AND DATE2
    Cette requête répond en 0,5 secondes au maximum. Ils y'a à peu près 800 000 lignes dans la réponse. (avec un explain, on voit qu'il utilise bien l'index.)

    Maintenant, on fait un DELETE sur cette table dans le même intervalle de temps : ça fait 2600 secondes que le delete est parti, il n'est toujours pas terminé...

    Pensez vous que cela soit normal??

    Je précise :

    - moteur de la table innodb
    - cette table référence 4 tables au moyen de foreign keys, mais n'est référencée par personne.

    D'avance merci pour vos tuyaux
    define: Programmeur : Celui qui résout un problème que vous n'aviez pas, d'une façon que vous ne comprenez pas.

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 719
    Points
    52 719
    Billets dans le blog
    5
    Par défaut
    1) donnez la liste intégrale des "autres colonnes" et non pas champs !
    2) donnez la liste intégrale des contraintes et index

    Sans cela il est impossible de vous aider !

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  3. #3
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Je pense qu'au cours du DELETE, il met à jour l'index en même temps, ce qui est lourd avec 70 millions de lignes.

    Essaie de désactiver les index avant de faire le DELETE puis de reconstruire l'index après :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    ALTER TABLE MaTable
    DISABLE KEYS;
     
    DELETE FROM MaTable
    WHERE ... ;
     
    ALTER TABLE MaTable
    ENABLE KEYS;
    Je crois que SQLPro a parlé d'une chose similaire dans un article sur l'indexation à propos d'INSERT massifs.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  4. #4
    Membre averti Avatar de GyZmoO
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2006
    Messages : 428
    Points : 301
    Points
    301
    Par défaut
    Bonjour et merci pour vos réponses.

    Voici la structure totale :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    CREATE TABLE MA_TABLE (
           PRI_ID          INTEGER NOT NULL,
           MY_DATE TIMESTAMP NOT NULL,
           MY_VALUE       DOUBLE NOT NULL,
           MY_STATUS      TINYINT NOT NULL,
           MONPAR_ID          INTEGER NOT NULL,
           CHKCOND_ID         INTEGER NOT NULL,
           SITE_NAME          VARCHAR(40) NULL,
           CHAIN_NAME         VARCHAR(40) NULL,
           MEAS_ANT_NAME      VARCHAR(40) NULL,
           RF_POLAR         TINYINT NULL,
           RF_TYPE			  TINYINT NULL,
           MY_RESTORATION_DATE		TIMESTAMP NULL,
           MY_RESTORATION_USE		BOOLEAN NOT NULL DEFAULT FALSE
    ) TYPE=INNODB;
     
    --
    -- Foreign keys
    --
     
    ALTER TABLE MY_TABLE
           ADD CONSTRAINT fk_my1 FOREIGN KEY (SITE_NAME, MEAS_ANT_NAME, RF_POLAR, RF_TYPE)
                                 REFERENCES T_PATH(SITE_NAME, MEAS_ANT_NAME, RF_POLAR, RF_TYPE) ;
     
    ALTER TABLE MY_TABLE
           ADD CONSTRAINT fk_my2 FOREIGN KEY (SITE_NAME, CHAIN_NAME)
                                 REFERENCES T_CHAIN(SITE_NAME, CHAIN_NAME) ;
     
     
    ALTER TABLE MY_TABLE
           ADD CONSTRAINT fk_my3 FOREIGN KEY (CHKCOND_ID)
                                 REFERENCES T_CONDITION(CHKCOND_ID) ;
     
     
    ALTER TABLE MY_TABLE
           ADD CONSTRAINT fk_my4 FOREIGN KEY (MONPAR_ID)
                                 REFERENCES T_PARAMETER(MONPAR_ID) ;
     
    --
    -- End foreign keys
    --
     
    --
    -- Primary key auto increment
    --
    ALTER TABLE MY_TABLE MODIFY COLUMN PRI_ID INTEGER NOT NULL AUTO_INCREMENT;
     
    --
    -- End primary key auto increment
    --
     
    --
    -- Index on MY_TABLE
    --
     
    CREATE INDEX IND_MY_TABLE_1 ON MY_TABLE
    (
           MY_DATE                      ASC
    );
     
    CREATE INDEX IND_MY_TABLE_2 ON MY_TABLE
    (
           MONPAR_ID                      ASC,
           MY_DATE            ASC
    );
     
    --
    -- End index on MY_TABLE
    --
    @SQLPro : voila pour la totalité des contraintes/index sur ma table .

    @CinePhil : On pensait cela également. Cependant, le fait de désactiver les contraintes puis de les reconstruire sera plus rapide?? Merci pour l'article, je vais le lire pour voir si je peux en tirer qq chose !
    define: Programmeur : Celui qui résout un problème que vous n'aviez pas, d'une façon que vous ne comprenez pas.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Août 2009
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 133
    Points : 117
    Points
    117
    Par défaut
    Supprimer les index sur une table pour faire un delete puis les remettre après n'est pas forcément une bonne chose dans le sens où pendant ce temps des requêtes de type SELECT peuvent s'effectuer sur la dite table et ne pourrons jouir des indexes, ce qui peut les rendre très longues.

    Ou bien me trompe-je?

  6. #6
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
           SITE_NAME          VARCHAR(40) NULL,
           CHAIN_NAME         VARCHAR(40) NULL,
           MEAS_ANT_NAME      VARCHAR(40) NULL,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ALTER TABLE MY_TABLE
           ADD CONSTRAINT fk_my1 FOREIGN KEY (SITE_NAME, MEAS_ANT_NAME, RF_POLAR, RF_TYPE)
                                 REFERENCES T_PATH(SITE_NAME, MEAS_ANT_NAME, RF_POLAR, RF_TYPE) ;
     
    ALTER TABLE MY_TABLE
           ADD CONSTRAINT fk_my2 FOREIGN KEY (SITE_NAME, CHAIN_NAME)
                                 REFERENCES T_CHAIN(SITE_NAME, CHAIN_NAME) ;
    C'est quoi ces clés étrangères multiples sur des VARCHAR ?
    Pas du tout optimisé pour une table de 70 millions de lignes !

    Et les colonnes clé étrangères ne sont pas indexées !

    Je crois que la lecture des articles de SQLPro sur l'indexation et le reste de son blog seront fort utiles !

    Citation Envoyé par ionesco
    Supprimer les index sur une table pour faire un delete puis les remettre après n'est pas forcément une bonne chose dans le sens où pendant ce temps des requêtes de type SELECT peuvent s'effectuer sur la dite table et ne pourrons jouir des indexes, ce qui peut les rendre très longues.

    Ou bien me trompe-je?
    Vu l'opération de DELETE qui est indiquée au premier message, j'ai plutôt l'impression qu'il s'agit d'une opération de maintenance à faire une fois, de préférence hors période d'exploitation de la table, préférenciellement en bloquant son utilisation durant l'opération, ce qui est je crois implicite pendant le DELETE mais qui doit je pense être explicitement programmé avec l'enchaînement des trois requêtes que j'ai proposées.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Août 2009
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 133
    Points : 117
    Points
    117
    Par défaut
    En effet dans le cadre d'une maintenance qui n'a pas lieu trop souvent, cela est fort recommander de droper les index puis les régénérer à la fin de notre opération.

  8. #8
    Membre averti Avatar de GyZmoO
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2006
    Messages : 428
    Points : 301
    Points
    301
    Par défaut
    Re.

    - Quand on déclare une FK, les colonnes correspondantes ne sont pas forcément indexées??!! !! ??

    - Sinon, en fait, la structure de la BD est vieille (c'est un vieux projet qui est malheureusement en exploitation), nous avons prévu de faire une refonte globale de la structure, mais là on essaye de faire des petites modifs pour optimiser un peu ... (Le client n'est pas content...)

    - De plus, encore malheureusement, cette requête DELETE doit pouvoir se faire en exploitation sans gêner les opérateurs... Du coup supprimer les index puis les remettre serait acceptable si le temps du DELETE était vraiment faible (de l'ordre de qqs minutes par exemple...)

    - Enfin, pourquoi est ce une mauvaise chose d'avoir des foreign key multiples sur des colonnes varchar?? Je veux bien comprendre que pour un index c'est pas terrible(si j'ai bien saisi, plus un index est petit, mieux c'est) mais pour une clé étrangère (si elles ne sont pas indexées...) ?? Le problème, c'est que pour le moment nous n'avons pas la possibilité de changer la structure des foreign key (et donc des primary keys associées) pour les convertir en "Integer auto increment"... C'est un peu la folie !

    Encore merci pour vos réponses.
    define: Programmeur : Celui qui résout un problème que vous n'aviez pas, d'une façon que vous ne comprenez pas.

  9. #9
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par GyZmoO Voir le message
    - Quand on déclare une FK, les colonnes correspondantes ne sont pas forcément indexées??!! !! ??
    Non, ce n'est pas implicite !
    Il faut déclarer les index.
    Ce qui est implicite, c'est l'index sur la première colonne en cas d'index multi-colonne (un index sur les colonnes (A, B) implique un index sur la colonne A mais pas sur la colonne B).
    Et bien sûr l'index sur la clé primaire puisque PRIMARY KEY est bel et bien un type particulier d'index, tout comme UNIQUE.

    - Sinon, en fait, la structure de la BD est vieille (c'est un vieux projet qui est malheureusement en exploitation), nous avons prévu de faire une refonte globale de la structure, mais là on essaye de faire des petites modifs pour optimiser un peu ... (Le client n'est pas content...)
    Il n'est pas content que vous ne fassiez que des petites modifs ?
    Faites un devis pour la migration !

    - De plus, encore malheureusement, cette requête DELETE doit pouvoir se faire en exploitation sans gêner les opérateurs... Du coup supprimer les index puis les remettre serait acceptable si le temps du DELETE était vraiment faible (de l'ordre de qqs minutes par exemple...)
    Testez le temps que ça prendrait de désactiver les index sur une autre base test avec la même structure. Peut-être que ça passera mais j'ai des doutes parce que j'ai souvenir de ce genre d'opération sur une table d'à peu près la même taille et c'était assez long de reconstruire l'index après coup. Mais c'était également long (potentiellement plus) de laisser l'index se modifier au cours du DELETE. Après, il y a peut-être d'autres techniques que je ne connais pas.

    - Enfin, pourquoi est ce une mauvaise chose d'avoir des foreign key multiples sur des colonnes varchar??
    Une foreign key fait référence à la clé primaire d'une (ou plusieurs) autre(s) table(s). Or une bonne clé primaire est de type entier non null non signé et auto-incrémentée (maintes fois débattu sur le forum). Si vous avez des clés étrangères en VARCHAR, c'est que les clés primaires de référence le sont aussi et ce n'est pas optimum, surtout avec une telle volumétrie.
    L'indexation sur un entier (4 octets) sera beaucoup plus petite et plus rapide que sur un VARCHAR(40) (40 ou 41 octets je ne sais plus).

    [quote)Le problème, c'est que pour le moment nous n'avons pas la possibilité de changer la structure des foreign key (et donc des primary keys associées) pour les convertir en "Integer auto increment"... [/QUOTE]
    Dommage !
    Et bon courage !
    Patience et longueur de temps font plus que force ni que rage ! (Jean de la Fontaine)
    Et vous risquez de devoir être très patient, selon les caractéristiques de votre serveur, pour cet opération. De mémoire, ce que j'évoquais plus haut dans des conditions similaires prenait plus d'une demie-heure en désactivant puis reconstruisant les index et encore plus longtemps sans les désactiver.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  10. #10
    Membre averti Avatar de GyZmoO
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2006
    Messages : 428
    Points : 301
    Points
    301
    Par défaut
    Merci pour ces réponses pertinentes!

    Donc avant de reprendre la structure globale de la BD pour faire les choses dans les rêgles de l'art (ça devient vital on dirait...), nous allons tenter 2 méthodes :

    - 1) Désactiver les index, faire le delete puis réactiver les index, on verra bien le temps que cela prendra.

    - 2) Nous comptions diviser cette requête en 10 plus petites, en théorie cela devrait nous faire gagner du temps, me trompe-je? (si Y est le temps du delete global et X le temps d'une des 10 "petites" requêtes, on a 10*X < Y, non?)

    Merci encore!
    define: Programmeur : Celui qui résout un problème que vous n'aviez pas, d'une façon que vous ne comprenez pas.

  11. #11
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par GyZmoO Voir le message
    - 2) Nous comptions diviser cette requête en 10 plus petites, en théorie cela devrait nous faire gagner du temps, me trompe-je? (si Y est le temps du delete global et X le temps d'une des 10 "petites" requêtes, on a 10*X < Y, non?)
    Pas sûr car il faudra reconstruire 10 fois l'index !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  12. #12
    Membre éprouvé Avatar de Oishiiii
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2009
    Messages
    508
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Août 2009
    Messages : 508
    Points : 1 104
    Points
    1 104
    Par défaut
    Bonjour,

    Juste quelque petites remarques.
    Citation Envoyé par CinePhil Voir le message
    Non, ce n'est pas implicite !
    Il faut déclarer les index.
    Ce qui est implicite, c'est l'index sur la première colonne en cas d'index multi-colonne (un index sur les colonnes (A, B) implique un index sur la colonne A mais pas sur la colonne B).
    Il me semble que ce n'est pas exact.
    MySQL (comme SQL Server il me semble, et peut-être d'autres) crée bien implicitement un index derrière chaque contrainte de clé étrangère.
    Comme écris dans la doc:
    InnoDB requires indexes on foreign keys [...] Such an index is created on the referencing table automatically if it does not exist.
    Un petit test pour vous en assurer:
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    create table pere (
      a integer primary key
    ) Engine=InnoDB;
     
    create table fils (
      b integer primary key,
      c integer,
      constraint fk_fils_pere foreign key (c)
         references pere(a)
    ) Engine=InnoDB;
     
    show indexes from fils;
    -- Retourne 2 indexs:  colonne b (PK) et colonne c (FK)

    Citation Envoyé par CinePhil Voir le message
    Et bien sûr l'index sur la clé primaire puisque PRIMARY KEY est bel et bien un type particulier d'index, tout comme UNIQUE.
    Les notions de clé primaire, contrainte d'unicité, clé étrangère ne devraient rien à voir avec les indexs (niveau logique vs niveau physique) mais malheureusement ce n'est pas le cas dans nos SGBDR..

  13. #13
    Membre averti Avatar de GyZmoO
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    428
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2006
    Messages : 428
    Points : 301
    Points
    301
    Par défaut
    Bonjour tous, et merci pour les réponses !

    Pas sûr car il faudra reconstruire 10 fois l'index !
    @CinePhil : Ouaip, effectivement, c'est peut être pas très malin... Pour info, notre requête s'est terminée en... tenez vous bien... 27 000 secondes ... (pour effacer les 800 000 lignes...)

    @Oishiiii : Effectivement, en faisant un show indexes, je vois bien des index sur les foreign keys !
    define: Programmeur : Celui qui résout un problème que vous n'aviez pas, d'une façon que vous ne comprenez pas.

  14. #14
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    50
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2007
    Messages : 50
    Points : 53
    Points
    53
    Par défaut
    peut aussi être bien dans certains cas, regarde la doc pour voir... Suivant les cas il faut faire un OPTIMIZE une fois que tu as terminé tout tes DELETE, ce qui peut aussi prendre un peu de temps.

  15. #15
    Membre à l'essai Avatar de laraki.fissel
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Mars 2012
    Messages
    42
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mars 2012
    Messages : 42
    Points : 23
    Points
    23
    Par défaut
    Bonjour

    je rebondis sur le sujet, j'ai le même problème avec une table de 1 500 000 lignes.
    un index est utilisé bien pour la requete SELECT mais pas pour le DELETE.

    explain select * from facture where annee='2016' and mois='07';

    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+-----------------------------+------------+------+---------------+-----------+---------+-------------+--------+----------+-------+
    | 1 | SIMPLE | facture | NULL | ref | annMois | annMois | 8 | const,const | 278218 | 100.00 | NULL |

    et

    explain delete from facture where annee='2016' and mois='07';
    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+-----------------------------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    | 1 | DELETE | facture | NULL | ALL | annMois | NULL | NULL | NULL | 1456213 | 100.00 | Using where |

    Merci pour votre aide

  16. #16
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 719
    Points
    52 719
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Oishiiii Voir le message
    Bonjour,

    Juste quelque petites remarques.

    Il me semble que ce n'est pas exact.
    MySQL (comme SQL Server il me semble, et peut-être d'autres) crée bien implicitement un index derrière chaque contrainte de clé étrangère.
    Non, non, non et NON !!!

    Pour MySQL cela dépend de la version puisque, il n'y a pas si longtemps les FK n'était pas active (on pouvait les créer, mais cela ne servait a rien !!!)
    Depuis une certaine version c'est effectivement ce qu'il fait mais c'est parfaitement imbécile dans un certain nombre de cas de figure...

    Pour SQL Server cela n'a jamais été vrai, comme dans tous les bons SGBDR (MySQL n'en étant pas vraiment un... à me lire : https://blog.developpez.com/sqlpro/p...oudre_aux_yeux

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  17. #17
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 719
    Points
    52 719
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par GyZmoO Voir le message
    Merci pour ces réponses pertinentes!

    Donc avant de reprendre la structure globale de la BD pour faire les choses dans les rêgles de l'art (ça devient vital on dirait...), nous allons tenter 2 méthodes :

    - 1) Désactiver les index, faire le delete puis réactiver les index, on verra bien le temps que cela prendra.

    - 2) Nous comptions diviser cette requête en 10 plus petites, en théorie cela devrait nous faire gagner du temps, me trompe-je? (si Y est le temps du delete global et X le temps d'une des 10 "petites" requêtes, on a 10*X < Y, non?)

    Merci encore!
    Il n'y a pas que cela... En effet toute opération de mise à jour des données, et le DELETE est une opération de mise à jour, possède différents effets de bord :
    1) journalisation : les données supprimées sont enregistrées dans le journal des transactions (fichier) au cas ou un problème survient. Faire différentes transaction génère plus d'entrée dans le JT... C'est donc moins rapide
    2) cache : pour que l'opération puisse être effectuée, il faut que toutes les lignes de table soient placées en cache. Cela oblige à dégager du cache d'autres données... C'est donc plus rapide

    Il y a donc un équilibre à trouver.

    Cependant je rejoins mes collègues sur l'imbécilité crasse que constitue des clefs sémantiques littérales. Faites une maquette en les remplaçant par des INT et vous diminuerez par au moins 10 le temps de ce DELETE !
    Parce qu'il ne faut pas oublier que chaque DELETE doit vérifier que la clef supprimée ne soit pas référencée par aucune des tables fille !!!!!!!

    Or des littéraux de 40 caractères et qui plus est des FK multi colonne c'est juste le crétinisme absolu... D'autant que ce connard de MySQmerde utilise 3 octets par caractères pour des tables créées dans une base de collation UTF8.. Ainsi vos FK1 et 2 ont une longueur de clef de 40 x3 + 40 x3 + ... > 240 octets !
    Or 240 octets c'est donc 30 passes dans le processeur pour lire une information et donc 60 passes pour comparer dans le pire des cas. En comparaisons avec un entier vous faites 2 passes.
    Donc un différentiel de vitesse de 30 au bas mot !!!!

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  18. #18
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut SQLPRO.

    Je ne sais pas si vous avez remarqué, mais vous répondez à Oishiiii, sur un message datant du 11 novembre 2009 ???

    Citation Envoyé par SQLPRO
    Pour MySQL cela dépend de la version puisque, il n'y a pas si longtemps les FK n'était pas active (on pouvait les créer, mais cela ne servait a rien !!!)
    Si MySql a créé une foreign Key et qu'elle n'est pas active, comment accéder à la table mère ? Je ne comprends pas votre réponse.
    Pourquoi MySql aurait mis en oeuvre cette fonctionnalité si on ne peut pas l'utiliser ?

    Et de quelle version MySql parlez-vous ? Bien sûr, je parle bien sûr de la version où vous avez rencontré ce problème.

    Citation Envoyé par SQLPRO
    Depuis une certaine version c'est effectivement ce qu'il fait mais c'est parfaitement imbécile dans un certain nombre de cas de figure...
    MySql fait quoi ? Pouvez-vous détailler votre affirmation ?
    Vous dites que c'est imbécile, je veux bien, mais il serait bien de détailler votre réponse afin de mieux vous comprendre.

    Citation Envoyé par SQLPRO
    Pour SQL Server cela n'a jamais été vrai
    Qu'est-ce qui n'est pas vrai ? Je ne comprends votre affirmation. Essayez d'être plus clair dans vos propos.

    Selon vous, MySql crée un index sur une foreign key ou pas ? Et sur Microsoft SQL Server est-ce aussi le cas ?

    Un index sur une foreign key sert que dans un seul cas, celui où l'on accès à la table fille en partant de la table mère.
    Or le cas général, consiste plutôt à partir de la table fille pour accéder à la table mère.
    Et donc la foreign key est largement suffisante pour ce type d'accès, et l'index sur celle-ci ne sert strictement à rien.
    Dois-je comprendre que votre NON signifie l'inutilité de l'index sur une foreign key ? Est-ce bien cela ?

    Par contre, je ne comprends pas trop pourquoi MySql crée un index sur une foreign key ?
    Je tiens tout de même à préciser que je n'ai pas créé cet index !
    Voici un cas réel sur la version MySql 5.7.18. J'ai créé une foreign key sur la table fils qui pointe sur la table père. Et voici la suppression de la foreign key :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    --------------
    SHOW INDEX FROM   `fils`
    --------------
     
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | fils  |          0 | PRIMARY  |            1 | fils_id     | A         |           4 |     NULL | NULL   |      | BTREE      |         |               |
    | fils  |          1 | FK_01    |            1 | pere_id     | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    --------------
    DROP INDEX `FK_01` on `fils`
    --------------
     
    ERROR 1553 (HY000) at line 5: Cannot drop index 'FK_01': needed in a foreign key constraint
    --------------
    commit
    --------------
     
    --------------
    SHOW INDEX FROM   `fils`
    --------------
     
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | fils  |          0 | PRIMARY  |            1 | fils_id     | A         |           4 |     NULL | NULL   |      | BTREE      |         |               |
    | fils  |          1 | FK_01    |            1 | pere_id     | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    --------------
    ALTER TABLE `fils` DROP FOREIGN KEY `FK_01`
    --------------
     
    --------------
    commit
    --------------
     
    --------------
    SHOW INDEX FROM   `fils`
    --------------
     
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | fils  |          0 | PRIMARY  |            1 | fils_id     | A         |           4 |     NULL | NULL   |      | BTREE      |         |               |
    | fils  |          1 | FK_01    |            1 | pere_id     | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    --------------
    DROP INDEX `FK_01` on `fils`
    --------------
     
    --------------
    commit
    --------------
     
    --------------
    SHOW INDEX FROM   `fils`
    --------------
     
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | fils  |          0 | PRIMARY  |            1 | fils_id     | A         |           4 |     NULL | NULL   |      | BTREE      |         |               |
    +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
     
    Appuyez sur une touche pour continuer...
    On remarque que supprimer en premier l'index ne fonctionne pas.
    Il faut en premier supprimer la foreign key pour pourvoir par la suite supprimer l'index.

    Donc Oishiiii avait bien raison et ne mérite pas ce -1.

    @ laraki.fissel : Quel est l'intérêt de déterrer un sujet datant de 2009 ???

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

Discussions similaires

  1. [AC-2010] DOcMD.runSQL beaucoup plus lent sur 2010 que sur 2003
    Par kaygee dans le forum VBA Access
    Réponses: 5
    Dernier message: 26/08/2013, 12h01
  2. "IF Exists" plus lent que "SELECT COUNT + IF"?!?
    Par Krison dans le forum Développement
    Réponses: 8
    Dernier message: 30/03/2012, 09h13
  3. Curseur plus performant que SELECT TOP 1 DELETE
    Par zinzineti dans le forum Administration
    Réponses: 4
    Dernier message: 12/07/2010, 12h15
  4. Réponses: 4
    Dernier message: 09/06/2008, 17h35
  5. [Firebird][Optimisation]Plus lent que le BDE!
    Par vincentj dans le forum Débuter
    Réponses: 3
    Dernier message: 07/02/2005, 15h48

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