MongoDB-Leistung im Vergleich zu PostgreSQL mit 5,5 Millionen Zeilen / Dokumenten


10

Kann mir jemand helfen, diese Abfragen zu vergleichen und zu erklären, warum die PostgreSQL-Abfrage in knapp 2000 ms ausgeführt wird und die MongoDB-Gesamtabfrage fast 9000 ms und manchmal bis zu 130 KB dauert?

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

PostgreSQL-Abfrage

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

MongoDB-Abfrage

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}
   }
])

Sowohl die PostgreSQL-Tabelle als auch die MongoDB-Auflistung sind auf datetime: 1 und locomotive_id: 1 indiziert

Diese Abfragen werden auf einem iMac mit einem 2-TB-Hybridlaufwerk und 16 GB Speicher getestet. Ich habe vergleichbare Ergebnisse auf einem Windows 7-Computer mit 8 GB Speicher und einer 256 GB SSD erhalten.

Vielen Dank!

** Update: Ich veröffentliche die EXPLAIN (BUFFERS, ANALYZE) Ergebnisse, nachdem meine Frage veröffentlicht wurde

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

** Update: Mongo erklären:

Erklären Sie aus 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
Für die PostgreSQL-Abfrage EXPLAIN (BUFFERS, ANALYZE)bitte Ausgabe anzeigen. Auch PostgreSQL-Version. (Ich habe dafür gestimmt, dies auf dba.SE zu verschieben)
Craig Ringer


2
Obwohl es schwierig ist, dem NoSQL-Hype zu entkommen, sind herkömmliche RDBMS jeden Tag besser und in Aggregaten weitaus ausgereifter. NoSQL-Datenbanken sind für die Indizierung und den Abruf von Primärschlüsseln nach Schlüsseln optimiert und nicht für diese Art von Abfragen.
Alexandros

Ich habe vielleicht ein kleines Detail ausgelassen. Jedes Dokument enthält über 200 Felder. Dies war ein direkter Import aus einer PostgreSQL-Datenbank. Viele der Feldwerte sind null. Ich erinnerte mich, dass MongoDB Nullwerte nicht besonders mochte. Ich habe einen weiteren Import mit <20 Feldern relevanter Daten durchgeführt und die Abfrageleistung ist um Größenordnungen besser. Ich erhalte <3000 ms auf einem Computer mit 8 GB Speicher und einer langsameren Festplatte. Ich werde in Kürze einen neuen Test auf einer viel leistungsstärkeren Maschine beginnen.
Mike A

Der Mongodb-Index {datetime: 1, prevdatetime: 1}sollte eine bessere Leistung als der aktuelle Index erzielen, da Mongodb nach Datum und Uhrzeit filtert. Dies würde die Anzahl der zu scannenden Dokumente verringern.
Rubish

Antworten:


8

Alles, was PostgreSQL hier tut, ist ein Bitmap-Heap-Scan bpkdmp_datetime_ix, um Blöcke zu finden, die möglicherweise übereinstimmende Zeilen enthalten, und dann ein Heap-Scan dieser Blöcke, um übereinstimmende Zeilen zu finden bpkdmp. Anschließend werden die Zeilen mithilfe von Hashes des Gruppierungsschlüssels in Hash-Buckets gruppiert, jeder Bucket summiert und die Ergebnisse sortiert. Es ist ein einfacher, grundlegender Abfrageplan - er funktioniert möglicherweise besser, wenn Sie viel darauf werfen work_mem, aber möglicherweise auch nicht.

Auch in dieser Abfrage gibt es keine Parallelität. es wird alles auf einem Kern passieren.

Ich kann nur davon ausgehen, dass MongoDB eine weniger effiziente Methode verwendet oder nicht von einem geeigneten Index profitiert. Sie müssten die explainfür die MongoDB-Abfrage anzeigen, damit dort ein nützlicher Kommentar möglich ist. siehe cursor.explain.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.