Prestazioni MongoDB rispetto a PostgreSQL con 5,5 milioni di righe / documenti


10

Qualcuno può aiutarmi a confrontare queste query e spiegare perché la query PostgreSQL viene eseguita in poco meno di 2000ms e la query aggregata MongoDB richiede quasi 9000ms e talvolta fino a 130K ms?

PostgreSQL 9.3.2 on x86_64-apple-darwin, compiled by i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00), 64-bit

Query PostgreSQL

SELECT locomotive_id,
   SUM(date_trunc('second', datetime) - date_trunc('second', prevDatetime)) AS utilization_time

FROM bpkdmp 
WHERE datetime >= '2013-7-26 00:00:00.0000' 
AND   datetime <= '2013-7-26 23:59:59.9999'
GROUP BY locomotive_id
order by locomotive_id

Query MongoDB

db.bpkdmp.aggregate([
   {
      $match : {
          datetime : { $gte : new Date(2013,6,26, 0, 0, 0, 0), $lt : new Date(2013,6,26, 23, 59, 59, 9999) }
   }
   },
   {
      $project: {
         locomotive_id : "$locomotive_id",
         loco_time : { $subtract : ["$datetime", "$prevdatetime"] }, 
      }
   },
   {
      $group : {
         _id : "$locomotive_id",
         utilization_time : { $sum : "$loco_time" }
      }
   },
   {
      $sort : {_id : 1}
   }
])

Sia la tabella PostgreSQL che la raccolta MongoDB sono indicizzate su datetime: 1 e locomotive_id: 1

Queste query sono in fase di test su un iMac con un'unità ibrida da 2 TB e 16 GB di memoria. Ho ricevuto risultati comparabili su una macchina Windows 7 con 8 GB di memoria e un SSD da 256 GB.

Grazie!

** Aggiornamento: sto pubblicando i risultati EXPLAIN (BUFFERS, ANALYZE) dopo che la mia domanda è stata pubblicata

"Sort  (cost=146036.84..146036.88 rows=19 width=24) (actual time=2182.443..2182.457 rows=152 loops=1)"
"  Sort Key: locomotive_id"
"  Sort Method: quicksort  Memory: 36kB"
"  Buffers: shared hit=13095"
"  ->  HashAggregate  (cost=146036.24..146036.43 rows=19 width=24) (actual time=2182.144..2182.360 rows=152 loops=1)"
"        Buffers: shared hit=13095"
"        ->  Bitmap Heap Scan on bpkdmp  (cost=12393.84..138736.97 rows=583942 width=24) (actual time=130.409..241.087 rows=559529 loops=1)"
"              Recheck Cond: ((datetime >= '2013-07-26 00:00:00'::timestamp without time zone) AND (datetime <= '2013-07-26 23:59:59.9999'::timestamp without time zone))"
"              Buffers: shared hit=13095"
"              ->  Bitmap Index Scan on bpkdmp_datetime_ix  (cost=0.00..12247.85 rows=583942 width=0) (actual time=127.707..127.707 rows=559529 loops=1)"
"                    Index Cond: ((datetime >= '2013-07-26 00:00:00'::timestamp without time zone) AND (datetime <= '2013-07-26 23:59:59.9999'::timestamp without time zone))"
"                    Buffers: shared hit=1531"
"Total runtime: 2182.620 ms"

** Aggiornamento: Mongo spiega:

Spiega da MongoDB

{
"serverPipeline" : [
    {
        "query" : {
            "datetime" : {
                "$gte" : ISODate("2013-07-26T04:00:00Z"),
                "$lt" : ISODate("2013-07-27T04:00:08.999Z")
            }
        },
        "projection" : {
            "datetime" : 1,
            "locomotive_id" : 1,
            "prevdatetime" : 1,
            "_id" : 1
        },
        "cursor" : {
            "cursor" : "BtreeCursor datetime_1",
            "isMultiKey" : false,
            "n" : 559572,
            "nscannedObjects" : 559572,
            "nscanned" : 559572,
            "nscannedObjectsAllPlans" : 559572,
            "nscannedAllPlans" : 559572,
            "scanAndOrder" : false,
            "indexOnly" : false,
            "nYields" : 1,
            "nChunkSkips" : 0,
            "millis" : 988,
            "indexBounds" : {
                "datetime" : [
                    [
                        ISODate("2013-07-26T04:00:00Z"),
                        ISODate("2013-07-27T04:00:08.999Z")
                    ]
                ]
            },
            "allPlans" : [
                {
                    "cursor" : "BtreeCursor datetime_1",
                    "n" : 559572,
                    "nscannedObjects" : 559572,
                    "nscanned" : 559572,
                    "indexBounds" : {
                        "datetime" : [
                            [
                                ISODate("2013-07-26T04:00:00Z"),
                                ISODate("2013-07-27T04:00:08.999Z")
                            ]
                        ]
                    }
                }
            ],
            "oldPlan" : {
                "cursor" : "BtreeCursor datetime_1",
                "indexBounds" : {
                    "datetime" : [
                        [
                            ISODate("2013-07-26T04:00:00Z"),
                            ISODate("2013-07-27T04:00:08.999Z")
                        ]
                    ]
                }
            },
            "server" : "Michaels-iMac.local:27017"
        }
    },
    {
        "$project" : {
            "locomotive_id" : "$locomotive_id",
            "loco_time" : {
                "$subtract" : [
                    "$datetime",
                    "$prevdatetime"
                ]
            }
        }
    },
    {
        "$group" : {
            "_id" : "$locomotive_id",
            "utilization_time" : {
                "$sum" : "$loco_time"
            }
        }
    },
    {
        "$sort" : {
            "sortKey" : {
                "_id" : 1
            }
        }
    }
],
"ok" : 1
}

1
Per la query PostgreSQL mostra l' EXPLAIN (BUFFERS, ANALYZE)output per favore. Inoltre, versione PostgreSQL. (Ho votato per passare a dba.SE)
Craig Ringer,


2
Sebbene sia difficile sfuggire alla campagna pubblicitaria NoSQL, i RDBMS tradizionali sono migliori e molto più maturi negli aggregati ogni giorno. I database NoSQL sono ottimizzati per l'indicizzazione e il recupero della chiave primaria per chiave e non per quel tipo di query.
Alexandros,

Potrei aver lasciato fuori un leggero dettaglio. Ci sono oltre 200 campi in ciascun documento. Questa era un'importazione diretta da un database PostgreSQL. Molti dei valori dei campi sono nulli. Ho ricordato che MongoDB non era particolarmente affezionato ai valori null. Ho effettuato un'altra importazione con <20 campi di dati rilevanti e le prestazioni della query sono notevolmente migliori. Ricevo <3000ms su una macchina con 8 GB di memoria e un HD più lento. Presto inizierò un nuovo test su una macchina molto più potente.
Mike A

L'indice Mongodb {datetime: 1, prevdatetime: 1}dovrebbe funzionare meglio dell'indice corrente, poiché i filtri mongodb su datetime e prevdatetime. Ridurrebbe il numero di documenti che devono essere scansionati.
rubish

Risposte:


8

Tutto ciò che PostgreSQL sta facendo qui è una scansione heap bitmap bpkdmp_datetime_ixper trovare blocchi che potrebbero contenere righe corrispondenti, quindi una scansione heap di quei blocchi per trovare le righe corrispondenti bpkdmp. Raggruppa quindi le righe in bucket hash utilizzando gli hash della chiave di raggruppamento, somma tutti i bucket e ordina i risultati. È un piano di query semplice e di base: potrebbe funzionare meglio se ne proverai molti work_mem, ma potrebbe anche non esserlo.

Non c'è neanche parallelismo da nessuna parte in quella query; accadrà tutto su un core.

Posso solo supporre che MongoDB stia utilizzando un metodo meno efficiente o che non stia beneficiando di un indice appropriato. Dovresti mostrare il explainper la query MongoDB per un possibile commento lì possibile; vedi cursor.explain.

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.