Czy ktoś może mi pomóc porównać te zapytania i wyjaśnić, dlaczego zapytanie PostgreSQL wykonuje się w niecałe 2000 ms, a zapytanie agregacyjne MongoDB zajmuje prawie 9000 ms, a czasem nawet 130 000 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
Zapytanie 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
Zapytanie 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}
}
])
Zarówno tabela PostgreSQL, jak i kolekcja MongoDB są indeksowane według datetime: 1 i locomotive_id: 1
Te zapytania są testowane na komputerze iMac z napędem hybrydowym 2 TB i 16 GB pamięci. Otrzymałem porównywalne wyniki na komputerze z systemem Windows 7 z 8 GB pamięci i dyskiem SSD 256 GB.
Dzięki!
** Aktualizacja: Publikuję wyniki WYJAŚNIENIA (BUFORY, ANALIZA) po opublikowaniu mojego pytania
"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"
** Aktualizacja: Mongo wyjaśni:
Wyjaśnij od 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
}
performance
mongodb
postgresql
Mike A.
źródło
źródło
EXPLAIN (BUFFERS, ANALYZE)
wyniki. Również wersja PostgreSQL. (Głosowałem za przeniesieniem tego na dba.SE){datetime: 1, prevdatetime: 1}
powinien działać lepiej niż bieżący indeks, ponieważ mongodb filtruje na datetime i prevdatetime. Zmniejszyłoby to liczbę dokumentów, które należy skanować.Odpowiedzi:
Wszystko, co robi tutaj PostgreSQL, to skanowanie stosu bitmap w
bpkdmp_datetime_ix
celu znalezienia bloków, które mogą zawierać pasujące wiersze, a następnie skanowanie stosu tych bloków w celu znalezienia pasujących wierszybpkdmp
. Następnie grupuje wiersze w segmenty mieszające za pomocą skrótów klucza grupującego, sumuje każde segmenty i sortuje wyniki. Jest to prosty, podstawowy plan zapytań - może działać lepiej, jeśli rzuciszwork_mem
na niego wiele , ale może też nie.W tym zapytaniu nigdzie też nie ma równoległości; wszystko stanie się na jednym rdzeniu.
Mogę tylko założyć, że MongoDB stosuje mniej wydajną metodę lub nie korzysta z odpowiedniego indeksu. Trzeba by pokazać
explain
zapytanie MongoDB, aby użyteczny komentarz był możliwy; zobcursor.explain
.źródło