2011-11-30 10 views
5

Ho un problema di throughput con le sequenze DELETE/INSERT su PostgreSQL 9.0. Sto cercando idee per migliorare la situazione.PostgreSQL DELETE/INSERT problema di throughput

Sull'hardware a nostra disposizione, POSSO INSERIRE nuove righe in un database a una velocità costante di 3000/s (uniformemente su 10 tabelle) ben oltre le righe di 1 m in ciascuna tabella in cui di solito collaudo. Tuttavia, se si passa a una modalità in cui CANCELLARE una riga e re-INSERISCI con dati diversi, le prestazioni diminuiscono di più di un ordine di grandezza a 250 righe/s (di nuovo, uniformemente su 10 tabelle).

Non ci sono vincoli su nessuna tabella. Ci sono 2 colonne indicizzate in ogni tabella con dimensione totale dell'indice (a 1 milione di righe per tabella) di 1 GB, che è comodamente all'interno dei shared_buffers (2 GB). La dimensione totale dei dati (a 1 milione di righe per tabella) è 12 GB, che è molto inferiore alla RAM totale del sistema. Questo è un database shadow in cui possiamo permetterci di ricostruire in emergenza, quindi eseguiamo fsync off.

Sembrerebbe che quando siamo in modalità popolare, beneficiamo di tempi di ricerca del disco molto bassi perché i dati vengono aggiunti. Tuttavia, quando passiamo alla modalità di aggiornamento, c'è un sacco di ricerca in corso (per eliminare le vecchie file presumibilmente). Il disco casuale cerca un costo di ~ 8ms (= ~ 125 al secondo). C'è un modo (senza un cambio di hardware) che possiamo migliorare significativamente le prestazioni delle operazioni UPDATE/re-INSERT?

EDIT1: Sto eseguendo test di perf per due piattaforme hardware di specifiche diverse. I numeri precedentemente citati provenivano dalla piattaforma con specifiche più elevate. Ho appena completato un test sulla piattaforma delle specifiche inferiori. In questo test inserisco nuove righe il più velocemente possibile, registrando la frequenza di inserimento ogni 10 secondi, finché non ho inserito 1 milione di righe. A questo punto il mio script di test passa ad aggiornare le righe casuali.

Perf results graph

Questo grafico mostra la frequenza di aggiornamento misurato era ~ 150 aggiornamenti di tutti i 10 tavoli/secondo durante la popolazione e la frequenza di aggiornamento è stato < 10 aggiornamenti di tutti i 10 tavoli/secondo.

@wildplasser - La macchina è una macchina reale, non una macchina virtuale. Le 10 tabelle hanno tutte lo schema seguente.

CREATE TABLE objecti_servicea_item1 
(
    iss_scs_id text, 
    iss_generation bigint, 
    boolattr1 boolean, 
    boolattr2 boolean, 
    boolattr3 boolean, 
    boolattr4 boolean, 
    boolattr5 boolean, 
    boolattr6 boolean, 
    boolattr7 boolean, 
    boolattr8 boolean, 
    boolattr9 boolean, 
    boolattr10 boolean, 
    boolattr11 boolean, 
    boolattr12 boolean, 
    boolattr13 boolean, 
    boolattr14 boolean, 
    boolattr15 boolean, 
    boolattr16 boolean, 
    boolattr17 boolean, 
    intattr1 bigint, 
    intattr2 bigint, 
    intattr3 bigint, 
    intattr4 bigint, 
    intattr5 bigint, 
    intattr6 bigint, 
    intattr7 bigint, 
    intattr8 bigint, 
    intattr9 bigint, 
    intattr10 bigint, 
    intattr11 bigint, 
    intattr12 bigint, 
    intattr13 bigint, 
    intattr14 bigint, 
    intattr15 bigint, 
    intattr16 bigint, 
    intattr17 bigint, 
    strattr1 text[], 
    strattr2 text[], 
    strattr3 text[], 
    strattr4 text[], 
    strattr5 text[], 
    strattr6 text[], 
    strattr7 text[], 
    strattr8 text[], 
    strattr9 text[], 
    strattr10 text[], 
    strattr11 text[], 
    strattr12 text[], 
    strattr13 text[], 
    strattr14 text[], 
    strattr15 text[], 
    strattr16 text[], 
    strattr17 text[] 
) 
WITH (
    OIDS=FALSE 
); 
CREATE INDEX objecti_servicea_item1_idx_iss_generation 
    ON objecti_servicea_item1 
    USING btree 
    (iss_generation); 
CREATE INDEX objecti_servicea_item1_idx_iss_scs_id 
    ON objecti_servicea_item1 
    USING btree 
    (iss_scs_id); 

Gli "Aggiornamenti" in corso comportano il seguente SQL per ciascuna delle 10 tabelle.

DELETE FROM ObjectI_ServiceA_Item1 WHERE iss_scs_id = 'ObjUID39' 
INSERT INTO ObjectI_ServiceA_Item1 
VALUES ('ObjUID39', '2', '0', NULL, '0' 
, NULL, NULL, NULL, '1', '1', NULL, '0' 
, NULL, NULL, NULL, NULL, '0', '1', '1' 
, '-70131725335162304', NULL, NULL, '-5241412302283462832' 
, NULL, '310555201689715409', '575266664603129486' 
, NULL, NULL, NULL, NULL, NULL, NULL 
, '-8898556182251816700', NULL, '3325820251460628173' 
, '-3434461681822953613' 
, NULL 
, E'{pvmo2mt7dma37roqpuqjeu4p8b,"uo1kjt1b3eu9g5vlf0d02l6iaq\\\\\\",",45kfns1j80gc7fri0dm29hnrjo}' 
, NULL, NULL 
, E'{omjv460do8cb7abn8t3eg5b6ki,"a7hrlninbk1rmu6h3rd4787l7f\\\\\\",",24n3ipfua5spma2vrj2aji98g3}' 
, NULL 
, E'{1821v2n2ermm4jujrucu5tekmm,"ukgst224964uhthkhjj9v189ft\\\\\\",",6dfsaniq9mftvbdr8g1sr8e6as}' 
, E'{c2a9gvf0fnd38m8vprlhkp2n74,"ts86vbat12lfr0d7l4tc29k9uk\\\\\\",",32b5j9r5evmrie4h21hi10dpot}' 
, E'{18pve4cmcbrjiom9bpvoo1l4n0,"hrqcsane6r0n7u2oj79bj605rh\\\\\\",",32q5n18q3qbkuit605fv47270o}' 
, E'{l3bf96shrpnnqgt35m7574t5n4,"cpol4k8296hbdqc9kac79oj0ua\\\\\\",",eqioulmb7vav10lbnc5jg752df}' 
, E'{5fai108h163hpjcv0ofgfi7c28,"ci958009ddak3li7bp37slcs8i\\\\\\",",2itstj01tkprlul8f530uhs6s2}' 
, E'{ueqfkdold8vc84jllr4b2cakt5,"t5vbea4r7tva091pa8j6886t60\\\\\\",",ul82aovhil1lpd290s14vd0p3i}' 
, NULL, NULL, NULL, NULL, NULL) 

Si noti che durante la prima fase del mio test di perf il comando DELETE non farà mai nulla.

@Frank Heikens - Nel test di prova che sto eseguendo gli aggiornamenti vengono eseguiti da 10 thread. Tuttavia, gli aggiornamenti vengono assegnati ai thread in modo da garantire che più aggiornamenti alla stessa riga vengano sempre gestiti dallo stesso thread.

+0

È una VM o una macchina reale? Inoltre, si prega di aggiungere (un frammento di) la definizione della tabella && query, e il piano di query risultante alla domanda. – wildplasser

+0

Hai controllato le serrature? Più processi potrebbero tentare di eliminare lo stesso record. –

+0

Ho modificato il mio post per rispondere al tuo commento. – mchr

risposta

3

Questa datamodel non è una bellezza, anche il DELETE - INSERT. Cosa c'è che non va con un UPDATE? Se iss_generation e iss_scs_id non cambiano in UPDATE, il database può fare un HOT update (tupla overflow di heap) per aumentare le prestazioni. AGGIORNAMENTO beneficerà anche di un fattore di riempimento inferiore.

Quando si esegue il DELETE di un record, tale record potrebbe trovarsi in un blocco diverso da quello in cui andrà INSERT. L'utilizzo di un fattore di riempimento inferiore e l'utilizzo di UPDATE potrebbero dare al database l'opzione di CANCELLARE e INSERIRE il record aggiornato nello stesso blocco sul disco. Ciò comporterà un I/O meno casuale.Quando è possibile utilizzare HOT, le cose vanno ancora meglio perché non è necessario aggiornare gli indici.

1

Non sicuro, ma forse cambiare il fattore di riempimento aiuterà?

+0

Grazie per il suggerimento - esaminerò questo. – mchr

0

Abbiamo successo con delete/copy da csv in memoria.

Problemi correlati