Ottimizza PostgreSQL per test rapidi


203

Sto passando a PostgreSQL da SQLite per una tipica applicazione Rails.

Il problema è che l'esecuzione delle specifiche è diventata lenta con PG.
Su SQLite ci sono voluti ~ 34 secondi, su PG sono ~ 76 secondi che è più di 2x più lento .

Quindi ora voglio applicare alcune tecniche per portare le prestazioni delle specifiche alla pari di SQLite senza modifiche al codice (idealmente semplicemente impostando le opzioni di connessione, che probabilmente non è possibile).

Un paio di cose ovvie dalla cima della mia testa sono:

  • Disco RAM (buona configurazione con RSpec su OSX sarebbe bello da vedere)
  • Tabelle non registrate (può essere applicato su tutto il database in modo da non modificare tutti gli script?)

Come avrai capito, non mi interessa l'affidabilità e il resto (qui il DB è solo una cosa da buttare).
Ho bisogno di ottenere il massimo dal PG e renderlo il più velocemente possibile .

La migliore risposta descriverebbe idealmente i trucchi per fare proprio questo, la configurazione e gli svantaggi di quei trucchi.

AGGIORNAMENTO: fsync = off + full_page_writes = offsolo tempo ridotto a ~ 65 secondi (~ -16 secondi). Buon inizio, ma lontano dall'obiettivo di 34.

AGGIORNAMENTO 2: Ho provato a utilizzare il disco RAM, ma il guadagno delle prestazioni era entro un margine di errore. Quindi non sembra valerne la pena.

AGGIORNAMENTO 3: * Ho trovato il più grande collo di bottiglia e ora le mie specifiche funzionano più velocemente di quelle di SQLite.

Il problema era la pulizia del database che ha fatto il troncamento . Apparentemente SQLite è troppo veloce lì.

Per "aggiustarlo" apro una transazione prima di ogni test e lo riavvolgo alla fine.

Alcuni numeri per ~ 700 test.

  • Troncamento: SQLite - 34s, PG - 76s.
  • Transazione: SQLite - 17s, PG - 18s.

2x aumento della velocità per SQLite. 4x aumento di velocità per PG.


2
Dubito davvero che riuscirai ad andare veloce come SQLite. SQLite con un singolo utente è follemente veloce. Il design di SQLite è molto veloce con conteggi degli utenti bassi e ridimensiona male; Il design di Pg si adatta bene, ma non è così veloce per un semplice lavoro di massa con un solo utente.
Craig Ringer,

1
Me ne rendo conto, ma c'è un caso particolare in cui spero di ottimizzare PG per (esecuzioni di test), quindi è il più veloce possibile. Non mi dispiace che sia leggermente più lento lì, ma 2.2x è un po 'troppo lento. Capito quello che intendo?
Dmytrii Nagirniak,

+1 Sarei molto interessato agli aggiornamenti sull'approccio del disco RAM se avessi dei risultati al riguardo.
Tscho,

@tscho Lo posterò sicuramente qui. Ma ho bisogno di un po 'di tempo dal momento che sto lavorando su altre cose e "ricercando" le cose PG in "background".
Dmytrii Nagirniak,

l' inserimento dei dati è un problema o una query ? Non è chiaro dalla tua domanda.
a_horse_with_no_name

Risposte:


281

Innanzitutto, usa sempre l'ultima versione di PostgreSQL. I miglioramenti delle prestazioni arrivano sempre, quindi probabilmente stai perdendo tempo se stai sintonizzando una versione precedente. Ad esempio, PostgreSQL 9.2 migliora significativamente la velocitàTRUNCATE e ovviamente aggiunge scansioni solo indice. Anche le versioni minori dovrebbero essere sempre seguite; vedere la politica della versione .

cosa non fare

Non NON mettere un tablespace su un ramdisk o altro supporto di memorizzazione non durevole .

Se si perde un tablespace, l'intero database potrebbe essere danneggiato e difficile da usare senza un lavoro significativo. C'è poco vantaggio in questo rispetto al solo utilizzo di UNLOGGEDtabelle e di avere comunque molta RAM per la cache.

Se vuoi veramente un sistema basato su ramdisk, initdbun cluster completamente nuovo sul ramdisk initdbinserendo una nuova istanza PostgreSQL sul ramdisk, quindi hai un'istanza PostgreSQL completamente usa e getta.

Configurazione del server PostgreSQL

Durante il test, è possibile configurare il server per un funzionamento non durevole ma più rapido .

Questo è uno degli unici usi accettabili per l' fsync=offimpostazione in PostgreSQL. Questa impostazione praticamente dice a PostgreSQL di non preoccuparsi delle scritture ordinate o di qualsiasi altra brutta protezione dell'integrità dei dati e della sicurezza degli arresti anomali, dandogli il permesso di eliminare completamente i tuoi dati se perdi energia o hai un crash del sistema operativo.

Inutile dire che non si dovrebbe mai abilitare fsync=offin produzione a meno che non si usi Pg come database temporaneo per i dati che è possibile rigenerare altrove. Se e solo se stai facendo per disattivare fsync puoi anche full_page_writesdisattivare, in quanto non fa più nulla di buono. Fai attenzione fsync=offe full_page_writesapplica a livello di cluster , in modo che influenzino tutti i database nell'istanza PostgreSQL.

Per l'uso in produzione è possibile utilizzare synchronous_commit=offe impostare un commit_delay, poiché si ottengono molti degli stessi vantaggi fsync=offsenza il rischio di corruzione dei dati giganti. Avrai una piccola finestra di perdita di dati recenti se abiliti il ​​commit asincrono, ma il gioco è fatto.

Se hai la possibilità di modificare leggermente il DDL, puoi anche usare le UNLOGGEDtabelle in Pg 9.1+ per evitare completamente la registrazione WAL e ottenere un vero aumento di velocità a costo di cancellazione delle tabelle in caso di crash del server. Non esiste alcuna opzione di configurazione per rendere tutte le tabelle non bloccate, deve essere impostato durante CREATE TABLE. Oltre ad essere utile per il test, questo è utile se in un database sono presenti tabelle piene di dati generati o non importanti che altrimenti contengono elementi che è necessario essere sicuri.

Controlla i tuoi registri e vedi se ricevi avvisi su troppi checkpoint. Se lo sei, dovresti aumentare i tuoi checkpoint_segments . Potresti anche voler mettere a punto checkpoint_completion_target per rendere più fluide le scritture.

Sintonizzati shared_buffersper adattarsi al tuo carico di lavoro. Questo dipende dal sistema operativo, dipende da cos'altro sta succedendo con il tuo computer e richiede alcuni tentativi ed errori. Le impostazioni predefinite sono estremamente conservative. Potrebbe essere necessario aumentare il limite massimo di memoria condivisa del sistema operativo se si aumenta shared_bufferssu PostgreSQL 9.2 e versioni precedenti ; 9.3 e versioni successive hanno cambiato il modo in cui usano la memoria condivisa per evitarlo.

Se stai usando solo un paio di connessioni che fanno molto lavoro, aumenta work_memper dare loro più RAM con cui giocare per sorta ecc. Fai attenzione che work_memun'impostazione troppo alta può causare problemi di memoria insufficiente perché non è per ordinamento per connessione, quindi una query può avere molti tipi nidificati. Hai solo davvero necessario aumentare work_memse è possibile vedere i tipi che si rovesciano su disco in EXPLAINo connesso con l' log_temp_filesimpostazione (consigliata), ma un valore più alto può anche lasciare Pg scegliere i piani più intelligenti.

Come detto da un altro poster, è saggio mettere l'xlog e le principali tabelle / indici su HDD separati, se possibile. Le partizioni separate sono piuttosto inutili, vuoi davvero unità separate. Questa separazione ha molti meno benefici se stai funzionando con fsync=offe quasi nessuno se stai usando le UNLOGGEDtabelle.

Infine, ottimizza le tue query. Assicurarsi che il proprio random_page_coste seq_page_costrifletta le prestazioni del proprio sistema, assicurarsi che effective_cache_sizesia corretto, ecc. Utilizzare EXPLAIN (BUFFERS, ANALYZE)per esaminare i singoli piani di query e attivare il auto_explainmodulo per segnalare tutte le query lente. Spesso è possibile migliorare notevolmente le prestazioni delle query semplicemente creando un indice appropriato o modificando i parametri di costo.

AFAIK non c'è modo di impostare un intero database o cluster come UNLOGGED. Sarebbe interessante poterlo fare. Considera di chiedere sulla mailing list di PostgreSQL.

Ottimizzazione del sistema operativo host

È possibile eseguire alcune regolazioni anche a livello di sistema operativo. La cosa principale che potresti voler fare è convincere il sistema operativo a non scaricare le scritture sul disco in modo aggressivo, dal momento che non ti importa davvero quando / se lo fanno sul disco.

In Linux è possibile controllare questo con il sottosistema della memoria virtuale 's dirty_*impostazioni, come dirty_writeback_centisecs.

L'unico problema con l'ottimizzazione delle impostazioni di writeback per essere troppo lento è che un flush di qualche altro programma può far sì che anche tutti i buffer accumulati di PostgreSQL vengano svuotati, causando grandi stalli mentre tutto blocca le scritture. Potresti essere in grado di alleviarlo eseguendo PostgreSQL su un file system diverso, ma alcuni flush possono essere a livello di dispositivo o a livello di intero host e non a livello di file system, quindi non puoi fare affidamento su questo.

Questa messa a punto richiede davvero di giocare con le impostazioni per vedere cosa funziona meglio per il tuo carico di lavoro.

Sui kernel più recenti, potresti voler assicurarti che vm.zone_reclaim_modesia impostato a zero, poiché può causare gravi problemi di prestazioni con i sistemi NUMA (la maggior parte dei sistemi al giorno d'oggi) a causa delle interazioni con la gestione di PostgreSQL shared_buffers.

Ottimizzazione di query e carichi di lavoro

Queste sono cose che richiedono modifiche al codice; potrebbero non essere adatti a te. Alcune sono cose che potresti applicare.

Se non stai raggruppando il lavoro in transazioni più grandi, inizia. Molte piccole transazioni sono costose, quindi dovresti raggruppare roba quando è possibile e pratico farlo. Se stai utilizzando il commit asincrono, questo è meno importante, ma comunque altamente raccomandato.

Quando possibile, utilizzare le tabelle temporanee. Non generano traffico WAL, quindi sono molto più veloci per inserimenti e aggiornamenti. A volte vale la pena assimilare un sacco di dati in una tabella temporanea, manipolarla come è necessario, quindi fare un INSERT INTO ... SELECT ...copia per copiarla nella tabella finale. Si noti che le tabelle temporanee sono per sessione; se la sessione termina o si perde la connessione, la tabella temporanea scompare e nessun'altra connessione può vedere il contenuto delle tabelle temporanee di una sessione.

Se stai usando PostgreSQL 9.1 o versioni successive, puoi utilizzare le UNLOGGEDtabelle per i dati che puoi permetterti di perdere, come lo stato della sessione. Questi sono visibili in diverse sessioni e conservati tra le connessioni. Vengono troncati se il server si spegne in modo impuro, quindi non possono essere utilizzati per nulla che non è possibile ricreare, ma sono ottimi per cache, viste materializzate, tabelle di stato, ecc.

In generale, non farlo DELETE FROM blah;. Usa TRUNCATE TABLE blah;invece; è molto più veloce quando scarichi tutte le righe in una tabella. Troncare molte tabelle in una TRUNCATEchiamata, se possibile. C'è un avvertimento se stai facendo un sacco TRUNCATESdi piccoli tavoli più e più volte, però; vedi: Velocità di troncamento Postgresql

Se non si hanno indici su chiavi esterne, DELETEi messaggi che coinvolgono le chiavi primarie a cui fanno riferimento quelle chiavi esterne saranno terribilmente lenti. Assicurati di creare tali indici se mai ti aspetti DELETEdalle tabelle di riferimento. Gli indici non sono richiesti per TRUNCATE.

Non creare indici che non ti servono. Ogni indice ha un costo di manutenzione. Prova a utilizzare un set minimo di indici e lascia che le scansioni dell'indice bitmap li combinino anziché mantenere troppi indici multi-colonna enormi e costosi. Dove sono richiesti gli indici, prova a popolare prima la tabella, quindi crea gli indici alla fine.

Hardware

Avere abbastanza RAM per contenere l'intero database è una grande vittoria se riesci a gestirlo.

Se non hai abbastanza RAM, più veloce è lo spazio di archiviazione, meglio è. Anche un SSD economico fa una differenza enorme rispetto alla ruggine che gira. Tuttavia, non fidarti degli SSD economici per la produzione, spesso non sono sicuri e potrebbero consumare i tuoi dati.

Apprendimento

Il libro di Greg Smith, PostgreSQL 9.0 High Performance rimane rilevante nonostante si riferisca a una versione un po 'più vecchia. Dovrebbe essere un riferimento utile.

Unisciti alla mailing list generale di PostgreSQL e seguila.

Lettura:


10
Posso anche raccomandare PostgreSQL 9.0 High Performance di @GregSmith, è davvero un'ottima lettura. Il libro tratta ogni aspetto dell'ottimizzazione delle prestazioni dal layout del disco all'ottimizzazione delle query e ti offre un'ottima comprensione degli interni PG.
Tscho,

10
Non ho rilasciato un aggiornamento del libro per PostgreSQL 9.1, l'unica versione dalla sua pubblicazione, perché non c'erano abbastanza cambiamenti relativi alle prestazioni in 9.1 per giustificarlo.
Greg Smith,

3
Ottimo commento. Proprio come un piccolo aggiornamento, "Potrebbe essere necessario aumentare il limite massimo di memoria condivisa del sistema operativo se aumenti shared_buffers" non è più vero (per la maggior parte degli utenti) in PostgreSQL 9.3: postgresql.org/docs/9.3/static/release-9- 3.html # AEN114343
Gunnlaugur Briem,

1
@brauliobo I miei test spesso fanno molti tx a TPS elevati ... perché provo a simulare la produzione, compresi i carichi di lavoro pesanti per la concorrenza. Se intendi "test lineare a connessione singola", sarei d'accordo con te.
Craig Ringer,

1
stackoverflow.com/questions/11419536/… DELETE può essere più veloce di TRUNCATE per le tabelle con poche righe, il che è probabilmente il caso dei test.
Jonathan Crosmer,

9

Usa layout del disco diverso:

  • disco diverso per $ PGDATA
  • disco diverso per $ PGDATA / pg_xlog
  • disco diverso per file tem (per database $ PGDATA / base // pgsql_tmp) (vedi nota su work_mem)

tweaks postgresql.conf:

  • shared_memory: 30% di RAM disponibile ma non più di 6 a 8 GB. Sembra essere meglio avere meno memoria condivisa (2 GB - 4 GB) per carichi di lavoro intensivi di scrittura
  • work_mem: principalmente per query selezionate con ordinamenti / aggregazioni. Questo è per impostazione della connessione e la query può allocare quel valore più volte. Se i dati non si adattano, viene utilizzato il disco (pgsql_tmp). Controlla "spiega analisi" per vedere quanta memoria hai bisogno
  • fsync e synchronous_commit: i valori predefiniti sono sicuri ma se riesci a tollerare i dati persi, puoi disattivare
  • random_page_cost: se si dispone di SSD o array RAID veloce, è possibile ridurlo a 2.0 (RAID) o addirittura inferiore (1.1) per SSD
  • checkpoint_segments: puoi andare più in alto 32 o 64 e cambiare checkpoint_completion_target su 0.9. Un valore inferiore consente un recupero post-crash più rapido

4
Nota che se stai già eseguendo fsync=off, mettere pg_xlog su un disco separato non migliora più molto.
intgr

Il valore di 1.1 per SSD sembra molto non qualificato. Riconosco che è ciò che alcuni professionisti hanno ciecamente raccomandato. Anche gli SSD sono significativamente più veloci per le letture sequenziali rispetto alle letture casuali.
Acumenus,

@ABB Sì, ma hai anche effetti di memorizzazione nella cache del buffer del sistema operativo al lavoro. Tutti quei parametri sono comunque un po 'mossi dalla mano ...
Craig Ringer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.