Domanda

Abbiamo una query per rimuovere alcune righe della tabella in base a un campo id (chiave primaria). Si tratta di una query piuttosto semplice:

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

Il problema è No. delle ids possono essere enormi (es. 70K), quindi la query richiede molto tempo. Esiste un modo per ottimizzare questo? (Stiamo utilizzando Sybase - se quello che conta).

È stato utile?

Soluzione

Consideriamo l'esecuzione di questo in lotti. Un ciclo in esecuzione 1000 record alla volta può essere molto più veloce di una query che fa tutto e in aggiunta non mantenere la tabella bloccato ad altri utenti per tutto il tempo a un tratto.

Se si dispone di eliminazione a catena (e un sacco di tavoli chiavi esterne interessate) o trigger coinvolti, potrebbe essere necessario per l'esecuzione in lotti ancora più piccoli. Dovrete experiement per vedere quale è il miglior numero per la situazione. Ho avuto le tabelle in cui ho dovuto eliminare in lotti di 100 e altri in cui lavoravano 50000 (fortuna in quel caso, come mi è stato l'eliminazione di un milione di record).

Ma in ogni anche io metterei i miei valori chiave che ho intenzione di eliminare in una tabella temporanea ed eliminare da lì.

Altri suggerimenti

Ci sono due modi per fare affermazioni come questa eseguire:

  1. Creare una nuova tabella e copiare tutti, ma le righe da eliminare. Scambia i tavoli dopo (alter table name ...) suggerisco di fare un tentativo anche quando sembra stupido. Alcuni database sono molto più veloci a copiare rispetto a sopprimere.

  2. partizionare i tavoli. Creare N tavoli e utilizzare al fine di unirsi a loro in una sola. Ordinare le righe in diverse tabelle raggruppati per il criterio di eliminazione. L'idea è di eliminare una intera tabella anziché eliminare singole righe.

Mi chiedo se il parsing una proposizione IN con 70K gli elementi in esso è un problema. Hai provato una tabella temporanea con un join, invece?

Può Sybase argomenti maniglia 70K a clausola? Tutti i database con cui ho lavorato hanno qualche limite sul numero di argomenti per la clausola IN. Ad esempio, Oracle ha limite intorno al 1000.

È possibile creare subselect invece di clausola? Che accorciare sql. Forse questo potrebbe aiutare per un numero così grande di valori nella clausola IN. Qualcosa di simile a questo:

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

L'eliminazione di gran numero di record può essere accelerato con alcuni interventi nel database, se modello di database permessi. Ecco alcune strategie:

  1. è possibile accelerare le cose facendo cadere gli indici, l'eliminazione di record e ricreare di nuovo gli indici. Ciò elimina gli alberi di indice di riequilibrio, mentre l'eliminazione di record.

    • cadere tutti gli indici sulla tabella
    • eliminare i record
    • indici ricreare
    • se hai un sacco di relazioni con questo tavolo, provare a disabilitare i vincoli se si è assolutamente sicuri che il comando di eliminazione non si romperà alcun vincolo di integrità. Eliminare andrà molto più veloce perché database non verrà controllo di integrità. Attivare i vincoli dopo eliminare.
    • disabilitare vincoli di integrità, disabilitare vincoli di controllo
    • eliminare i record
    • attivare i vincoli
    • trigger disabilitare sul tavolo, se avete qualsiasi e se le regole di business consentono questo. Eliminare i record, quindi attivare i trigger.

    • ultimo, fare come altre suggerito - fare una copia della tabella che contiene le righe che non devono essere cancellati, poi cadere originale, rinominare la copia e ricreare i vincoli di integrità, se ce ne sono.

Vorrei provare combinazione di 1, 2 e 3. Se questo non funziona, quindi 4. Se tutto è lento, cercherei grande scatola -. Più memoria, dischi più veloci

Scopri cosa sta utilizzando le prestazioni!

In molti casi si potrebbe utilizzare una delle soluzioni fornite. Ma ci potrebbero essere altri (basato sulla conoscenza di Oracle, quindi le cose saranno diverse su altri database Edit:. Appena visto che lei ha citato Sybase):

  • Hai chiavi esterne su quel tavolo? Si assicura che gli ID che si riferiscono sono indicizzati
  • Hai indici su quel tavolo? Potrebbe essere che droping prima di eliminare e ricreare dopo l'eliminazione potrebbe essere più veloce.
  • verificare il piano di esecuzione. E 'utilizzando un indice in cui una scansione completa della tabella potrebbe essere più veloce? O viceversa? CONSIGLI potrebbe aiutare
  • al posto di un selezionato in new_table come suggerito sopra un tavolo di creare come selezionare potrebbe essere ancora più veloce.

Ma ricordate:. Scopri cosa sta utilizzando le prestazioni prima

Quando si utilizza istruzioni DDL Assicurati di comprendere e accettare le conseguenze che potrebbe avere sulle transazioni e backup.

Prova l'ordinamento l'ID si passa in "in" nello stesso ordine come il tavolo, o l'indice è memorizzato in. Si può quindi ottenere più visite per la cache del disco.

Mettere l'ID da cancellare in una tabella temporanea che ha l'Ids ordinato nello stesso ordine della tabella principale, può lasciare che il database di fare una semplice digitalizzata sul tavolo principale.

Si potrebbe provare a utilizzare più di una connessione e spiting il lavoro nel corso dei collegamenti in modo da utilizzare tutte le CPU sul server di database, tuttavia pensare a quello che saranno prese fuori serrature ecc prima.

Penso anche che la tabella temporanea è probabile che la soluzione migliore.

Se si dovesse fare un "cancellare dalla .. dove ID in (select id da ...)" può ancora essere lento con query di grandi dimensioni, però. Ho quindi suggerisco che si elimina utilizzando un join -. Molte persone non conoscono che la funzionalità

Quindi, data questa tabella di esempio:

    -- 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

Possiamo quindi scrivere il nostro codice di eliminazione come segue:

    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

Lo our_table avere un riferimento sul delete cascade?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top