2010-10-24 16 views
6

Ho il seguente semplice tabella che contiene i dati di misurazione del traffico:Molto lento bitmap mucchio scansione in Postgres

CREATE TABLE "TrafficData" 
(
    "RoadID" character varying NOT NULL, 
    "DateID" numeric NOT NULL, 
    "ExactDateTime" timestamp NOT NULL, 
    "CarsSpeed" numeric NOT NULL, 
    "CarsCount" numeric NOT NULL 
) 
CREATE INDEX "RoadDate_Idx" ON "TrafficData" USING btree ("RoadID", "DateID"); 

La colonna RoadID identifica in modo univoco la strada i cui dati sono in corso di registrazione, mentre DateID identifica il giorno dell'anno (1..365) dei dati - fondamentalmente una rappresentazione arrotondata di ExactDateTime.

Ho circa 100.000.000 di file; ci sono 1.000 valori distinti nella colonna "RoadID" e 365 valori distinti nella colonna "DateID".

ho quindi eseguire la seguente query:

SELECT * FROM "TrafficData" 
WHERE "RoadID"='Station_1' 
AND "DateID">20100610 AND "DateID"<20100618; 

Ciò richiede fino a tre secondi da capogiro per finire, e non posso per la vita di me capire perché.

EXPLAIN ANALYZE mi dà il seguente risultato:

Bitmap Heap Scan on "TrafficData" (cost=104.84..9743.06 rows=2496 width=47) (actual time=35.112..2162.404 rows=2016 loops=1) 
    Recheck Cond: ((("RoadID")::text = 'Station_1'::text) AND ("DateID" > 20100610::numeric) AND ("DateID" < 20100618::numeric)) 
    -> Bitmap Index Scan on "RoadDate_Idx" (cost=0.00..104.22 rows=2496 width=0) (actual time=1.637..1.637 rows=2016 loops=1) 
     Index Cond: ((("RoadID")::text = 'Station_1'::text) AND ("DateID" > 20100610::numeric) AND ("DateID" < 20100618::numeric)) 
Total runtime: 2163.985 ms 

mie specifiche:

  • di Windows 7
  • Postgres 9.0
  • 4GB di RAM

mi piacerebbe molto apprezzare qualsiasi pozzo utile TERS!

+0

Questa non è la tabella che si sta utilizzando, non esiste una colonna "StationId". –

+0

Ah, vero; Grazie per la segnalazione. StationID == RoadID. Colpa mia. Ho appena cambiato il nome della colonna nella definizione della tabella per rendere i contenuti più intuitivi, ma non è riuscito a cambiare il nome nella definizione della query e l'output della query. Ho aggiornato la domanda per includere il nome corretto della colonna. – TroutKing

+0

Hai il vuoto in funzione o lo hai disattivato? –

risposta

0
  • RAM da 4 GB -> 6+ si dispone di record di 100 M, che non è grande ma potrebbe importare una memoria della macchina desktop. Se questo non è un desktop, io non sono sicuro perché si avrebbe una piccola quantità di memoria
  • AND "DateID">20100610 AND "DateID"<20100618; ->DateID BETWEEN 20100611 AND 20100617;
  • Creare un indice sul DateID
  • sbarazzarsi di tutti i doppi apici campo nomi
  • Invece di un varchar fanno RoadID un campo di testo
+0

L'aggiornamento della RAM non è un'opzione, sfortunatamente. Anche la RAM in più non dovrebbe fare alcuna differenza, dal momento che i file indice sono già "piccoli" abbastanza da poter essere caricati in memoria. Ho anche provato DateID tra, purtroppo non ha fatto alcuna differenza. – TroutKing

+0

bene anche tu vuoi creare un indice sul DateID; vedere le aggiunte – vol7ron

+0

A destra, ho aggiunto un indice su DateID. Purtroppo nessuna differenza. – TroutKing

5

la parte lenta è obviosly il recupero dei dati dalle tabelle, poiché l'accesso dell'indice sembra essere molto veloce. È possibile ottimizzare i parametri di utilizzo della RAM (vedere e http://www.varlena.com/GeneralBits/Tidbits/perf.html) o ottimizzare il layout dei dati nella tabella emettendo un comando CLUSTER (vedere http://www.postgresql.org/docs/8.3/static/sql-cluster.html).

CLUSTER "TrafficData" USING "RoadDate_Idx"; 

dovrebbe farlo.

+0

Ho provato questo ieri, ma ho dovuto rinunciare quando il comando CLUSTER era ancora in esecuzione dopo undici ore. – TroutKing

+2

Holla ... Forse una selezione semplice ordinata in un'altra potrebbe essere più veloce?Se CLUSTER è così lento, sembra davvero un problema io, e i dati non sembrano affatto corrispondenti all'indice. Se puoi, prova questo sull'hardware della classe server ... – Daniel

2

In aggiunta alla risposta di Daniel, l'operazione cluster è un processo singolo che ha riorganizzato i dati su disco. L'intento è di ottenere le tue 2000 righe di risultati da un minor numero di blocchi del disco.

Dato che si tratta di dati fittizi, per capire come è possibile richiederlo rapidamente, si consiglia di ricaricarlo, in uno schema più vicino al modo in cui verrà caricato mentre viene generato. Immagino che i dati vengano generati un giorno alla volta, il che si tradurrà in una forte correlazione tra DateID e la posizione su disco. In questo caso, eseguirò il cluster su DateID oppure dividerò i dati di test in 365 carichi separati e li ricaricherò.

Senza di esso e avendo generato dati casualmente, è molto probabile che si debbano eseguire più di 2000 ricerche della testina del disco.

Vorrei anche controllare che qualsiasi altra cosa che stai usando su Windows 7 non stia aggiungendo tempo a quelle letture che non ti servono, come ad esempio assicurarti che i blocchi letti non contengano le firme dei virus o che eseguano contemporaneamente una deframmentazione del disco programmata automaticamente (con la testa del disco quasi mai vicino a dove era l'ultima volta che un blocco del database è stato letto).