고성능

동시성 동작: 몽고DB와 카우치베이스 비교

Couchbase - MongoDB

다중 사용자 테스트

 

의 데이비드 글래서 Meteor몽고DB 쿼리에서 일치하는 문서가 누락된 블로그 문제 문제가 발생했습니다. MongoDB MMAPv1과 MongoDB WiredTiger 엔진 모두에서 이 문제를 재현하는 것은 간단합니다. 그의 글에서 얻은 결론은 다음과 같습니다(강조는 제 의견입니다).

 

간단히 말해서...

  • 이 문제는 ID로 문서를 조회하는 쿼리와 같이 인덱스를 사용하지 않는 쿼리에는 영향을 미치지 않습니다.

  • 인덱스 키에 사용된 모든 필드에 대해 명시적으로 단일 값 동일성 일치를 수행하는 쿼리에는 영향을 미치지 않습니다.

  • 문서가 처음 삽입된 후 필드가 수정되지 않는 인덱스를 사용하는 쿼리에는 영향을 미치지 않습니다.

  • 하지만 다른 종류의 몽고DB 쿼리는 일치하는 모든 문서를 포함하지 못할 수 있습니다!

 

이를 바라보는 또 다른 방법이 있습니다. 몽고DB에서 동시 작업이 진행 중일 때 쿼리가 보조 인덱스(_id가 아닌 다른 인덱스)를 사용하여 두 개의 문서를 검색할 수 있다면 결과가 잘못될 수 있습니다. 이는 많은 데이터베이스 애플리케이션에서 흔히 볼 수 있는 시나리오입니다.

 

테스트는 다음과 같습니다:

  1. 컨테이너를 만듭니다: 버킷, 테이블 또는 컬렉션.

  2. 30만 개의 문서와 같은 작은 데이터 집합으로 데이터를 로드합니다.

  3. 필터링하려는 필드(술어)에 인덱스를 만듭니다.

  4. 한 세션에서 인덱싱된 필드를 업데이트하고 다른 세션에서 쿼리합니다.

 

MongoDB 테스트

 

MongoDB에서 문제를 재현하는 단계:

 

  1. MongoDB 3.2를 설치합니다.

  2. MMAPv1 또는 WiredTiger로 몽고드를 불러옵니다.

  3. tpcc.py를 사용하여 데이터 로드

  4. python tpcc.py -warehouses 1 -no-execute mongodb

  5. 카운트 가져오기

> tpcc 사용

> db.ORDER_LINE.find().count();

299890

  1. db.ORDER_LINE.ensureIndex({state:1});

 

MongoDB 실험 1: 더 높은 값으로 업데이트하기

 

상태 필드를 aaaaaa 값으로 설정한 다음 이 값을 zzzzzz로 동시에 업데이트하고 필드와 일치하는 두 개의 값['aaaaaa','zzzzzz']을 가진 총 문서 수를 쿼리합니다. 인덱싱된 필드의 값이 낮은 값(aaaaaa)에서 높은 값(zzzzzz)으로 이동하면 이러한 항목은 B-트리의 한쪽에서 다른 쪽으로 이동합니다. 이제 스캔이 중복된 값을 반환하는지, 더 높은 count() 값으로 변환되는지 확인하려고 합니다.

 

> db.ORDER_LINE.update({OL_DIST_INFO:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 299890, "nUpserted" : 0, "nModified" : 299890 })

> db.ORDER_LINE.find({state:{$in:['aaaaaa','zzzzzz']}}).count();

299890

 

> db.ORDER_LINE.find({state:{$in:['aaaaaa','zzzzzz']}}).explain();

{

    "queryPlanner" : {

        "plannerVersion" : 1,

        "네임스페이스" : "tpcc.ORDER_LINE",

        "indexFilterSet" : false,

        "parsedQuery" : {

            "state" : {

                "$in" : [

                    "아아아아아",

                    "zzzzzz"

                ]

            }

        },

        "winningPlan" : {

            "stage" : "FETCH",

            "inputStage" : {

                "stage" : "IXSCAN",

                "keyPattern" : {

                    "state" : 1

                },

                "indexName" : "state_1",

                "isMultiKey" : false,

                "방향" : "앞으로",

                "indexBounds" : {

                    "state" : [

                        "["아아아아아", "아아아아아"]",

                        "["쯔쯔", "쯔쯔"]"

                    ]

                }

            }

        },

        "rejectedPlans" : [ ]

    },

    "serverInfo" : {

        "호스트" : "케샤브-맥북-프로-로컬",

        "port" : 27017,

        "version" : "3.0.2",

        "gitVersion" : "6201872043ecbbc0a4cc169b5482dcf385fc464f"

    },

    "OK" : 1

}

 
  1. 업데이트 문 1: 모든 문서를 상태 = "zzzzzz"로 설정하도록 업데이트합니다.

       db.ORDER_LINE.update({OL_DIST_INFO:{$gt:""}}),

                     {$set: {상태: "zzzzzz"}}, {multi:true});

 

  1. 업데이트 문 2: 모든 문서를 상태 = "aaaaaa"로 설정하도록 업데이트합니다.

 db.ORDER_LINE.update({OL_DIST_INFO:{$gt:""}}),

                     {$set: {상태: "aaaaaa"}}, {multi:true});

 

  3. 카운트 문: Count documents:(state in ["aaaaaa", "zzzzzz"])

      db.ORDER_LINE.find({state:{$in:['aaaaaa','zzzzzz']}}).count();

 

 
 

시간

세션 1: 이슈 업데이트 성명서1

(업데이트 상태 = "zzzzz")

세션 2: 이슈 카운트 명세서를 계속 발행합니다.

T0

업데이트 문 시작

Count = 299890

T1

업데이트 성명 계속

Count = 312736

T2

업데이트 성명 계속

Count = 312730

T3

업데이트 성명 계속

Count = 312778

T4

업데이트 성명 계속

Count = 312656

T4

업데이트 성명 계속

Count = 313514

T4

업데이트 성명 계속

Count = 303116

T4

업데이트 내역 완료

Count = 299890

 

결과: 이 시나리오에서는 인덱스가 많은 문서를 이중으로 계산하여 실제보다 더 많은 문서를 보고합니다.

 

원인: B-Tree의 리프 레벨에 있는 데이터가 정렬됩니다. B-Tree가 aaaaaa에서 zzzzz로 업데이트되면 아래쪽 끝에 있는 키가 위쪽 끝으로 이동합니다. 동시 스캔은 이 이동을 인식하지 못합니다. MongoDB는 안정적인 스캔을 구현하지 않고 항목이 들어오는 대로 계산합니다. 따라서 많은 업데이트가 진행되는 프로덕션 시스템에서는 동일한 문서를 두 번, 세 번 또는 그 이상으로 계산할 수 있습니다. 이는 동시 작업에 따라 달라집니다.

 

몽고DB 실험 2: 낮은 값으로 업데이트하기

역방향 작업을 수행하여 데이터를 'zzzzzz'에서 'aaaaaa'로 업데이트해 보겠습니다. 이 경우 인덱스 항목이 더 높은 값에서 더 낮은 값으로 이동하므로 스캔에서 일부 적격 문서가 누락되어 과소 계수된 것으로 표시됩니다.

 

시간

세션 1: 이슈 업데이트 성명서2

(업데이트 상태 = "아아아아아")

세션 2: 이슈 카운트 명세서를 계속 발행합니다.

T0

업데이트 문 시작

Count = 299890

T1

업데이트 성명 계속

Count = 299728

T2

업데이트 성명 계속

Count = 299750

T3

업데이트 성명 계속

Count = 299780

T4

업데이트 성명 계속

Count = 299761

T4

업데이트 성명 계속

Count = 299777

T4

업데이트 성명 계속

Count = 299815

T4

업데이트 내역 완료

Count = 299890

 

결과: 이 시나리오에서는 인덱스가 많은 문서를 누락하고 실제보다 적은 수의 문서를 보고합니다.

 

원인: 역효과가 발생합니다. 값이 zzzzzz인 키가 aaaaaa로 수정되면 항목이 B-Tree의 상위 끝에서 하위 끝으로 이동합니다. 다시 말하지만, 스캔의 안정성이 없기 때문에 상위 끝에서 하위 끝으로 이동한 키를 놓칠 수 있습니다.

 

MongoDB 실험 3: 동시 업데이트

 

두 세션이 인덱싱된 필드를 동시에 지속적으로 업데이트합니다. 이 경우, 이전 관찰에 따르면 각 세션에서 오버카운트 및 언더카운트 문제가 모두 발생합니다. MongoDB는 값을 변경한 업데이트만 보고하기 때문에 nModified 결과가 달라집니다.

 

그러나 수정된 문서의 총 개수는 299980개를 넘지 않습니다. 따라서 MongoDB는 동일한 문서를 두 번 업데이트하는 것을 방지하여 고전적인 할로윈 문제. 안정적인 스캔이 없기 때문에 이 다중 업데이트 문에서 업데이트된 objectID 목록을 유지 관리하고 동일한 객체가 적격 문서로 나타나면 업데이트를 피하는 방식으로 이 문제를 처리하는 것으로 추정됩니다.

 

세션 1

 

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 299890, "nUpserted" : 0, "nModified" : 299890 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 303648, "nUpserted" : 0, "nModified" : 12026 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 194732, "nUpserted" : 0, "nModified" : 138784 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 334134, "nUpserted" : 0, "nModified" : 153625 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 184379, "nUpserted" : 0, "nModified" : 146318 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 335613, "nUpserted" : 0, "nModified" : 153403 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 183559, "nUpserted" : 0, "nModified" : 146026 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 335238, "nUpserted" : 0, "nModified" : 149337 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 187815, "nUpserted" : 0, "nModified" : 150696 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 335394, "nUpserted" : 0, "nModified" : 154057 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 188774, "nUpserted" : 0, "nModified" : 153279 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 334408, "nUpserted" : 0, "nModified" : 155970 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 299890, "nUpserted" : 0, "nModified" : 0 })

>

 

세션 2:

 

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 302715, "nUpserted" : 0, "nModified" : 287864 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 195248, "nUpserted" : 0, "nModified" : 161106 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 335526, "nUpserted" : 0, "nModified" : 146265 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 190448, "nUpserted" : 0, "nModified" : 153572 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 336734, "nUpserted" : 0, "nModified" : 146487 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 189321, "nUpserted" : 0, "nModified" : 153864 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 334793, "nUpserted" : 0, "nModified" : 150553 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 186274, "nUpserted" : 0, "nModified" : 149194 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 336576, "nUpserted" : 0, "nModified" : 145833 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 183635, "nUpserted" : 0, "nModified" : 146611 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state:"zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 336904, "nUpserted" : 0, "nModified" : 143920 })

>

카우치베이스 테스트

 

  1. Couchbase 4.5를 설치합니다.

  1. tpcc.py를 사용하여 데이터 로드

  2. python tpcc.py -warehouses 1 -no-execute n1ql

  3. 카운트 가져오기

> order_line에서 count(*)를 선택합니다;

    300023

  1. ORDER_LINE(state)에 인덱스 i1을 생성합니다;

  2. UPDATE ORDER_LINE SET state = 'aaaaaa';

 

카우치베이스 실험 1: 더 높은 값으로 업데이트하기

 

초기 설정을 수행합니다.

> UPDATE ORDER_LINE SET state = 'aaaaaa' WHERE OL_DIST_INFO > "";

 

상태 필드(속성)의 값이 "aaaaaa"인 값이 300023인지 확인합니다.

 

> select count(1) a_cnt FROM ORDER_LINE where state = 'aaaaaa'

 모두 통합

 SELECT count(1) z_cnt FROM ORDER_LINE where state = 'zzzzzz';

   "결과": [

       {

           "a_cnt": 300023

       },

       {

           "z_cnt": 0

       }

   ],

 

쿼리에서 인덱스 스캔이 수행되는지 확인해 보겠습니다.  

EXPLAIN SELECT COUNT(1) AS totalcnt

주문_라인에서

WHERE state = 'aaaaaa' 또는 state = 'zzzzzz';

             "~어린이": [

                   {

                       "1TP5운영자": "DistinctScan",

                       "scan": {

                           "1TP5운영자": "IndexScan",

                           "커버": [

                               "커버 ((ORDER_LINE.상태))”,

                               "커버 ((메타(ORDER_LINE).id))”

                           ],

                           "index": "i2",

                           "index_id": "665b11a6c36d4136",

                           "키스페이스": "ORDER_LINE",

                           "네임스페이스": "기본값",

                           "스팬": [

                               {

                                   "범위": {

                                       "높음": [

                                           ""아아아아아""

                                       ],

                                       "포함": 3,

                                       "낮음": [

                                           ""아아아아아""

                                       ]

                                   }

                               },

                               {

                                   "범위": {

                                       "높음": [

                                           ""zzzzz""

                                       ],

                                       "포함": 3,

                                       "낮음": [

                                           ""zzzzz""

                                       ]

                                   }

                               }

                           ],

                           "사용": "gsi"

                       }

                   },

 

또한 두 개의 개별 술어(state = 'aaaaaa')와 (state = 'zzzzzz')의 UNION ALL을 사용하여 인덱스 수를 효율적으로 계산할 수 있습니다.  

 

cbq> explain select count(1) a_cnt

주문_라인에서

여기서 state = 'aaaaaa'

모두 통합

SELECT COUNT(1) Z_CNT

주문_라인에서

여기서 state = 'zzzzzz';

{

   "요청ID": “ef99e374-48f5-435c-8d54-63d1acb9ad22”,

   "서명": "json",

   "결과": [

       {

           "plan": {

               "1TP5운영자": "UnionAll",

               "어린이": [

                   {

                       "1TP5운영자": "시퀀스",

                       "~어린이": [

                           {

                               "1TP5운영자": "인덱스 카운트 스캔",

                               "커버": [

                                   "커버 ((ORDER_LINE.상태))”,

                                   "커버 ((메타(ORDER_LINE).id))”

                               ],

                               "index": "i2",

                               "index_id": "665b11a6c36d4136",

                               "키스페이스": "ORDER_LINE",

                               "네임스페이스": "기본값",

                               "스팬": [

                                   {

                                       "범위": {

                                           "높음": [

                                               ""아아아아아""

                                           ],

                                           "포함": 3,

                                           "낮음": [

                                               ""아아아아아""

                                           ]

                                       }

                                   }

                               ],

                               "사용": "gsi"

                           },

                           {

                               "1TP5운영자": "인덱스 카운트 프로젝트",

                               "결과_기간": [

                                   {

                                       "as": "a_cnt",

                                       "expr": "count(1)"

                                   }

                               ]

                           }

                       ]

                   },

                   {

                       "1TP5운영자": "시퀀스",

                       "~어린이": [

                           {

                               "1TP5운영자": "인덱스 카운트 스캔",

                               "커버": [

                                   "커버 ((ORDER_LINE.상태))”,

                                   "커버 ((메타(ORDER_LINE).id))”

                               ],

                               "index": "i2",

                               "index_id": "665b11a6c36d4136",

                               "키스페이스": "ORDER_LINE",

                               "네임스페이스": "기본값",

                               "스팬": [

                                   {

                                       "범위": {

                                           "높음": [

                                               ""zzzzz""

                                           ],

                                           "포함": 3,

                                           "낮음": [

                                               ""zzzzz""

                                           ]

                                       }

                                   }

                               ],

                               "사용": "gsi"

                           },

                           {

                               "1TP5운영자": "인덱스 카운트 프로젝트",

                               "결과_기간": [

                                   {

                                       "as": "z_cnt",

                                       "expr": "count(1)"

                                   }

                               ]

                           }

                       ]

                   }

               ]

           },

           "text": "select count(1) a_cnt FROM ORDER_LINE where state = 'aaaaaa' UNION ALL select count(1) z_cnt FROM ORDER_LINE where state = 'zzzzzz'"

       }

   ],

   "상태": "성공",

   "metrics": {

       "elapsedTime": "2.62144ms",

       "실행 시간": "2.597189ms",

       "resultCount": 1,

       "결과 크기": 3902

   }

}

 

상태 필드를 aaaaaa 값으로 설정합니다. 그런 다음 이 값을 zzzzzz로 업데이트하고 두 값 중 하나를 사용하여 총 문서 수를 동시에 쿼리합니다.

 

세션 1: 상태 필드를 zzzzzz 값으로 업데이트하기

 

UPDATE ORDER_LINE SET state = 'zzzzzz' WHERE OL_DIST_INFO > "";

{    "mutationCount": 300023 }

 

세션 2: ORDER_LINE에서 'aaaaaa' 및 'zzzzzz'의 개수를 쿼리합니다.

 

시간

세션 1: 이슈 업데이트 성명서1

(업데이트 상태 = "zzzzz")

a_cnt

z_cnt

합계

T0

업데이트 문 시작

300023

0

300023

T1

업데이트 성명 계속

288480

11543

300023

T2

업데이트 성명 계속

259157

40866

300023

T3

업데이트 성명 계속

197167

102856

300023

T4

업데이트 성명 계속

165449

134574

300023

T5

업데이트 성명 계속

135765

164258

300023

T6

업데이트 성명 계속

86584

213439

300023

T7

업데이트 내역 완료

0

300023

300023

 

결과: 데이터가 업데이트될 때 인덱스 업데이트가 이루어집니다. 값이 'aaaaaa'에서 'zzzzzz'로 마이그레이션될 때 이중으로 계산되지 않습니다.  

 

카우치베이스 인덱스는 정기적으로 인덱스를 스냅샷하여 안정적인 스캔을 제공합니다. 이는 상당한 엔지니어링 노력이 필요하지만, 이번 호에서 살펴본 것처럼 극심한 동시성 상황에서도 안정적인 응답을 제공합니다.

 

인덱스 스캔이 검색하는 데이터는 포인트 스캔이 시작된 시점의 데이터입니다. 동시에 들어오는 후속 업데이트는 반환되지 않습니다. 이는 또 다른 수준의 안정성을 제공합니다.

 

각 인덱스 스캔에 대해 스캔의 안정성이 제공된다는 점에 유의하세요. 인덱스는 200밀리초마다 스냅샷을 생성합니다. 동일 또는 여러 인덱스에 대한 여러 인덱스 스캔이 포함된 장기 실행 쿼리가 있는 경우, 쿼리는 여러 스냅샷을 사용할 수 있습니다. 따라서 장기 실행 쿼리에서 서로 다른 인덱스 스캔은 각각 다른 결과를 반환합니다. 이 사용 사례는 향후 릴리즈에서 단일 쿼리의 여러 스캔에서 동일한 스냅샷을 사용하도록 개선될 예정입니다.

카우치베이스 실험 2: 더 낮은 값으로 업데이트하기

 

'zzzzzz'에서 'aaaaaa'로 데이터를 다시 업데이트하는 역연산을 해보겠습니다.

 

세션 1: 상태 필드를 값 aaaaaa로 업데이트하기

 

UPDATE ORDER_LINE SET state = 'aaaaaa' WHERE OL_DIST_INFO > "";

{ "mutationCount": 300023 }

 

세션 2: ORDER_LINE에서 'aaaaaa' 및 'zzzzzz'의 개수를 쿼리합니다.

 

시간

세션 1: 이슈 업데이트 성명서1

(업데이트 상태 = "아아아아아")

a_cnt

z_cnt

합계

T0

업데이트 문 시작

0

300023

300023

T1

업데이트 성명 계속

28486

271537

300023

T2

업데이트 성명 계속

87919

212104

300023

T3

업데이트 성명 계속

150630

149393

300023

T4

업데이트 성명 계속

272358

27665

300023

T5

업데이트 성명 계속

299737

286

300023

T6

업데이트 내역 완료

0

300023

300023

 

카우치베이스 실험 3: 동시 업데이트

 

두 개의 세션이 색인된 필드를 동시에 지속적으로 업데이트합니다. 인덱스를 안정적으로 스캔하면 항상 적격 문서의 전체 목록이 반환됩니다: 30023을 반환하고 Couchbase는 모든 문서를 업데이트하고 변경 횟수를 30023으로 보고합니다. 업데이트는 이전 값이 새 값과 동일한지 여부에 관계없이 업데이트가 이루어집니다.

 

세션 1:

 

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

 

세션 2:

 

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'aaaaaa' 여기서 state > "";

{ "mutationCount": 300023 }

업데이트 ORDER_LINE set state = 'zzzzzz'여기서 state > "";

{ "mutationCount": 300023 }

결론

 

MongoDB:

  1. 인덱스의 한 부분에서 다른 부분(상위에서 하위)으로 데이터를 이동하는 동시 업데이트가 있는 경우 MongoDB 쿼리는 문서를 놓치게 됩니다.

  2. 인덱스의 한 부분에서 다른 부분(하위에서 상위)으로 데이터를 이동하는 동시 업데이트가 있는 경우, MongoDB 쿼리는 동일한 문서를 여러 번 반환합니다.

  3. MongoDB에서 동시에 여러 번 업데이트하면 동일한 문제가 발생하여 필요한 모든 문서를 업데이트하지 못할 수 있지만, 한 문장에서 동일한 문서를 두 번 업데이트하는 것은 방지할 수 있습니다.

  4. MongoDB를 사용하는 애플리케이션을 개발할 때는 각 쿼리에 대해 하나의 문서만 선택하고 업데이트하도록 데이터 모델을 설계해야 합니다. 동시 업데이트가 있을 경우 잘못된 결과가 반환되므로 MongoDB에서 다중 문서 쿼리는 피하세요.

 

카우치베이스:

 

  1. Couchbase는 동시 업데이트가 있는 경우에도 예상되는 적격 문서 수를 반환합니다. Couchbase의 안정적인 인덱스 스캔은 MongoDB가 제공하지 않는 애플리케이션에 대한 보호 기능을 제공합니다.

  2. 동시 업데이트는 안정적인 인덱스 스캔의 이점을 누리며 신청서가 발행될 때 모든 적격 서류를 처리합니다.

감사

이 작업에 대한 검토와 귀중한 의견을 제공해 주신 Couchbase 인덱싱 팀의 Sriram Melkote와 Deepkaran Salooja에게 감사드립니다.

참조

 

  1. MongoDB 강력한 일관성: https://www.mongodb.com/nosql-explained

  2. 몽고DB 동시성: https://docs.mongodb.com/manual/faq/concurrency/

  3. MongoDB 쿼리가 항상 일치하는 모든 문서를 반환하는 것은 아닙니다!  https://engineering.meteor.com/mongodb-queries-dont-always-return-all-matching-documents-654b6594a827#.s9y0yheuv

  4. 카우치베이스: https://www.couchbase.com

  5. N1QL:  https://query.couchbase.com

 

이 문서 공유하기
받은 편지함에서 카우치베이스 블로그 업데이트 받기
이 필드는 필수 입력 사항입니다.

작성자

게시자 케샤브 머시

케샤브 머시는 Couchbase R&D의 부사장입니다. 이전에는 MapR, IBM, Informix, Sybase에서 근무했으며 데이터베이스 설계 및 개발 분야에서 20년 이상의 경력을 쌓았습니다. IBM Informix에서 SQL 및 NoSQL R&D 팀을 이끌었습니다. Couchbase에서 두 번의 President's Club 상을, IBM에서 두 번의 뛰어난 기술 업적상을 수상했습니다. 인도 마이소르 대학교에서 컴퓨터 과학 및 공학 학사 학위를 받았으며, 24개의 미국 특허를 보유하고 있습니다.

댓글 남기기

카우치베이스 카펠라를 시작할 준비가 되셨나요?

구축 시작

개발자 포털에서 NoSQL을 살펴보고, 리소스를 찾아보고, 튜토리얼을 시작하세요.

카펠라 무료 사용

클릭 몇 번으로 Couchbase를 직접 체험해 보세요. Capella DBaaS는 가장 쉽고 빠르게 시작할 수 있는 방법입니다.

연락하기

카우치베이스 제품에 대해 자세히 알고 싶으신가요? 저희가 도와드리겠습니다.