Question

Nous avons une requête pour supprimer certaines lignes de la table basée sur un champ identifiant (clé primaire). Il est une question assez simple:

delete all from OUR_TABLE where ID in (123, 345, ...)

Le problème est numeros ids peut être énorme (par ex. 70k), de sorte que la requête prend beaucoup de temps. Est-il possible d'optimiser cela? (Nous utilisons sybase - si cela importe).

Était-ce utile?

La solution

Pensez à l'exécution de ce en lots. Une boucle en cours d'exécution 1000 enregistrements à la fois peut être beaucoup plus rapide d'une requête qui fait tout et en plus ne gardera pas la table verrouillé à d'autres utilisateurs aussi longtemps à un étirement.

Si vous avez suppression en cascade (et beaucoup de tableaux clés étrangers affectés) ou déclencheurs impliqués, vous devrez peut-être exécuter par lots encore plus petits. Vous devrez Experiement pour voir qui est le meilleur numéro pour votre situation. J'ai eu des tables où je devais supprimer en lots de 100 et d'autres où travaillaient 50000 (la chance dans ce cas que je supprimait un million de disques).

Mais en tout, même je mettrais mes valeurs clés que je compte supprimer dans une table temporaire et supprimer de là.

Autres conseils

Il y a deux façons de faire des déclarations comme celle-ci exécutent:

  1. Créer une nouvelle table et copiez tous, mais les lignes à supprimer. Intervertir les tables après (alter table name ...) Je vous suggère de faire un essai, même quand il semble stupide. Certaines bases de données sont beaucoup plus rapides à la copie qu'à supprimer.

  2. partitionner vos tables. Créez des tableaux N et utiliser en vue de les rejoindre en un seul. Trier les lignes dans des tables différentes regroupées par le critère de suppression. L'idée est de laisser tomber une table entière au lieu de supprimer des lignes individuelles.

Je me demande si l'analyse d'une clause IN avec 70K éléments qu'il est un problème. Avez-vous essayé une table temporaire avec une jointure au lieu?

peut les arguments de poignée 70K Sybase clause IN? Toutes les bases de données avec lesquels je travaillais ont une certaine limite sur le nombre d'arguments en faveur de la clause de IN. Par exemple, Oracle ont limite autour de 1000.

Pouvez-vous créer subselect au lieu de clause IN? Cela raccourcira sql. Peut-être que cela pourrait aider pour un si grand nombre de valeurs dans la clause IN. Quelque chose comme ceci:

  DELETE FROM OUR_TABLE WHERE ID IN 
        (SELECT ID FROM somewhere WHERE some_condition)

Suppression grand nombre d'enregistrements peut être accéléré avec quelques interventions dans la base de données, si les permis de modèle de base de données. Voici quelques stratégies:

  1. vous pouvez accélérer les choses en laissant tomber les index, la suppression d'enregistrements et de recréer à nouveau les index. Cela permettra d'éliminer les arbres indice de rééquilibrage tout en supprimant les enregistrements.

    • supprimer tous les index sur la table
    • supprimer des enregistrements
    • index recréent
    • si vous avez beaucoup de relations à ce tableau, essayez de désactiver les contraintes si vous êtes absolument sûr que la commande de suppression ne cassera pas une contrainte d'intégrité. Supprimer ira beaucoup plus vite, car la base de données ne sera pas vérifier l'intégrité. Activer contraintes supprimer après.
    • désactiver les contraintes d'intégrité, désactivez les contraintes de vérification
    • supprimer des enregistrements
    • enable contraintes
    • Désactiver les déclencheurs sur la table, si vous avez une et si vos règles métier permettent que. Supprimer les enregistrements, puis activer les déclencheurs.

    • dernier, faire comme d'autres suggéré - faire une copie de la table qui contient des lignes qui ne sont pas à supprimer, puis déposez-original, renommer copie et recréer les contraintes d'intégrité, s'il y a lieu.

Je voudrais essayer combinaison de 1, 2 et 3. Si cela ne fonctionne pas, alors 4. Si tout est lent, je chercherais plus grande boîte -. Plus de mémoire, des disques plus rapides

Découvrez ce qui utilise la performance!

Dans de nombreux cas, vous pouvez utiliser l'une des solutions proposées. Mais il pourrait y avoir d'autres (basée sur la connaissance Oracle, donc les choses seront différentes sur d'autres bases de données Edit:. Venez de voir que vous avez mentionné sybase):

  • Avez-vous des clés étrangères sur cette table? Vérifie que les ids référence sont indexés
  • Avez-vous des indices sur cette table? Il se pourrait que droping avant de supprimer et de recréer après la suppression pourrait être plus rapide.
  • vérifier le plan d'exécution. Est-ce à l'aide d'un index où un scan de table pourrait être plus rapide? Ou l'inverse? TRUCS pourraient aider
  • au lieu d'une sélection dans new_table comme suggéré ci-dessus une table créer comme select pourrait être encore plus rapide.

Mais rappelez-vous. Découvrez ce qui utilise d'abord l'exécution

Lorsque vous utilisez des instructions DDL assurez-vous de comprendre et d'accepter les conséquences qu'elle pourrait avoir sur les transactions et les sauvegardes.

Essayez de tri l'ID que vous passez dans « dans » dans le même ordre que la table ou index est stocké. Vous pouvez alors obtenir plus de visites sur le cache disque.

Mettre l'ID à supprimer dans une table temporaire qui a les Ids triés dans le même ordre que la table principale, peut laisser la base de données faire un simple numérisée sur la table principale.

Vous pouvez essayer d'utiliser plus d'une connexion et spiting le travail sur les connexions de manière à utiliser toutes les CPU sur le serveur de base de données, pensez toutefois à ce que les serrures seront retirés etc en premier.

Je pense aussi que la table temporaire est probablement la meilleure solution.

Si vous deviez faire « supprimer .. où ID dans (select id de ...) » il peut encore être lent avec de grandes requêtes, bien que. Je suggère donc de supprimer l'aide d'une jointure -. Beaucoup de gens ne connaissent pas cette fonctionnalité

Alors, étant donné cet exemple tableau:

    -- set up tables for this example
    if exists (select id from sysobjects where name = 'OurTable' and type = 'U')
        drop table OurTable
    go

    create table OurTable (ID integer primary key not null)
    go
    insert into OurTable (ID) values (1)
    insert into OurTable (ID) values (2)
    insert into OurTable (ID) values (3)
    insert into OurTable (ID) values (4)
    go

On peut alors écrire notre code de suppression comme suit:

    create table #IDsToDelete (ID integer not null)
    go
    insert into #IDsToDelete (ID) values (2)
    insert into #IDsToDelete (ID) values (3)
    go
    -- ... etc ...
    -- Now do the delete - notice that we aren't using 'from'
    -- in the usual place for this delete
    delete OurTable from #IDsToDelete
       where OurTable.ID = #IDsToDelete.ID
    go
    drop table #IDsToDelete
    go
    -- This returns only items 1 and 4
    select * from OurTable order by ID
    go

Est-ce que our_table une référence suppression en cascade?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top