550 만 개의 행 / 문서를 가진 MongoDB 성능 및 PostgreSQL


10

누군가이 쿼리를 비교하고 PostgreSQL 쿼리가 2000ms 미만으로 실행되는 이유를 설명하고 MongoDB 집계 쿼리가 거의 9000ms, 때로는 최대 130Kms가 걸리는 이유를 설명 할 수 있습니까?

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 쿼리

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 쿼리

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

PostgreSQL 테이블과 MongoDB 컬렉션은 모두 datetime : 1 및 locomotive_id : 1에 색인화됩니다.

이 쿼리는 2TB 하이브리드 드라이브와 16GB 메모리를 갖춘 iMac에서 테스트 중입니다. 8GB의 메모리와 256GB SSD를 갖춘 Windows 7 컴퓨터에서 비슷한 결과를 얻었습니다.

감사!

** 업데이트 : 질문을 게시 한 후 EXPLAIN (BUFFERS, ANALYZE) 결과를 게시하고 있습니다

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

** 업데이트 : 몽고 설명 :

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
PostgreSQL 쿼리 쇼 EXPLAIN (BUFFERS, ANALYZE)출력은 다음을 참조하십시오. 또한 PostgreSQL 버전입니다. (나는 이것을 dba.SE로 옮기기로 투표했다)
Craig Ringer

... 그리고 MongoDB 계획에 대한 정보? docs.mongodb.org/manual/reference/method/cursor.explain
Craig Ringer

2
NoSQL 과대 광고를 피하기는 어렵지만, 전통적인 RDBMS는 하루 종일 집계가 더 좋고 훨씬 더 성숙합니다. NoSQL 데이터베이스는 기본 쿼리 인덱싱 및 키별 검색에 최적화되어 있으며 이러한 종류의 쿼리에는 적합하지 않습니다.
Alexandros

약간의 세부 사항을 생략했을 수 있습니다. 각 문서에는 200 개가 넘는 필드가 있습니다. 이것은 PostgreSQL 데이터베이스에서 직접 가져 왔습니다. 많은 필드 값이 널입니다. MongoDB가 특히 null 값을 좋아하지 않는다는 것을 상기했습니다. <20 필드의 관련 데이터로 다른 가져 오기를 수행했으며 쿼리 성능이 훨씬 우수합니다. 8GB의 메모리와 느린 HD를 가진 컴퓨터에서 <3000ms를 받고 있습니다. 훨씬 더 강력한 머신에서 곧 새로운 테스트를 시작할 것입니다.
Mike A

mongodb 인덱스 {datetime: 1, prevdatetime: 1}는 datetime 및 prevdatetime을 필터링하므로 현재 인덱스보다 성능이 우수해야합니다. 스캔해야하는 문서 수가 줄어 듭니다.
rubish

답변:


8

PostgreSQL에서 수행하는 모든 작업은 bpkdmp_datetime_ix일치하는 행을 포함 할 수있는 블록을 찾기 위해 비트 맵 힙 스캔을 수행 한 다음에서 일치하는 행을 찾기 위해 해당 블록을 힙 스캔 bpkdmp합니다. 그런 다음 그룹화 키의 해시를 사용하여 행을 해시 버킷으로 그룹화하고 각 버킷을 합산하고 결과를 정렬합니다. 단순하고 기본적인 쿼리 계획입니다. 많은 쿼리를 처리하면 성능이 향상 될 수 work_mem있지만 그렇지 않을 수도 있습니다.

해당 쿼리의 어느 곳에도 병렬 처리가 없습니다. 그것은 모두 하나의 핵심에서 일어날 것입니다.

MongoDB가 덜 효율적인 방법을 사용하고 있거나 적절한 색인을 사용하지 않는다고 가정 할 수 있습니다. explain유용한 의견이 있으려면 MongoDB 쿼리에 대해 를 표시해야 합니다. 참조하십시오 cursor.explain.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.