我正在尝试从索引集合中获取一些记录,但太多 总是检查 key
这是我的查询
db.getCollection('transactions').find({"vout.address" : { "$in":['LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd']} , _id: {$lt: '5e232dec225b5b1c61057ddb'}})
.limit(10).sort({blocknumber: -1 , _id: -1}).hint({ 'vout.address': -1, 'blocknumber': -1, '_id': -1 }).explain();
我的索引:
vout.address_-1_blocknumber_-1__id_-1
解释返回以下内容:
{ queryPlanner:
{ plannerVersion: 1,
namespace: 'blockchain.ltc_transactionsTable',
indexFilterSet: false,
parsedQuery:
{ '$and':
[ { 'vout.address': { '$eq': 'LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd' } },
{ _id:
{ '$lt':
ObjectID {
_bsontype: 'ObjectID',
id:
Buffer [Uint8Array] [ 94, 35, 45, 236, 34, 91, 91, 28, 97, 5, 125, 219 ] } } } ] },
winningPlan:
{ stage: 'LIMIT',
limitAmount: 10,
inputStage:
{ stage: 'FETCH',
inputStage:
{ stage: 'IXSCAN',
keyPattern: { 'vout.address': -1, blocknumber: -1, _id: -1 },
indexName: 'vout.address_-1_blocknumber_-1__id_-1',
isMultiKey: true,
multiKeyPaths: { 'vout.address': [ 'vout' ], blocknumber: [], _id: [] },
isUnique: true,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds:
{ 'vout.address':
[ '["LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd", "LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd"]' ],
blocknumber: [ '[MaxKey, MinKey]' ],
_id:
[ '(ObjectId(\'5e232dec225b5b1c61057ddb\'), ObjectId(\'000000000000000000000000\')]' ] } } } },
rejectedPlans: [] },
executionStats:
{ executionSuccess: true,
nReturned: 10,
executionTimeMillis: 2,
totalKeysExamined: 911,
totalDocsExamined: 10,
executionStages:
{ stage: 'LIMIT',
nReturned: 10,
executionTimeMillisEstimate: 0,
works: 912,
advanced: 10,
needTime: 901,
needYield: 0,
saveState: 7,
restoreState: 7,
isEOF: 1,
limitAmount: 10,
inputStage:
{ stage: 'FETCH',
nReturned: 10,
executionTimeMillisEstimate: 0,
works: 911,
advanced: 10,
needTime: 901,
needYield: 0,
saveState: 7,
restoreState: 7,
isEOF: 0,
docsExamined: 10,
alreadyHasObj: 0,
inputStage:
{ stage: 'IXSCAN',
nReturned: 10,
executionTimeMillisEstimate: 0,
works: 911,
advanced: 10,
needTime: 901,
needYield: 0,
saveState: 7,
restoreState: 7,
isEOF: 0,
keyPattern: { 'vout.address': -1, blocknumber: -1, _id: -1 },
indexName: 'vout.address_-1_blocknumber_-1__id_-1',
isMultiKey: true,
multiKeyPaths: { 'vout.address': [ 'vout' ], blocknumber: [], _id: [] },
isUnique: true,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds:
{ 'vout.address':
[ '["LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd", "LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd"]' ],
blocknumber: [ '[MaxKey, MinKey]' ],
_id:
[ '(ObjectId(\'5e232dec225b5b1c61057ddb\'), ObjectId(\'000000000000000000000000\')]' ] },
keysExamined: 911,
seeks: 902,
dupsTested: 10,
dupsDropped: 0 } } },
allPlansExecution: [] },
keyId: Long { _bsontype: 'Long', low_: 1, high_: 1570062499 } } },
operationTime:
Timestamp { _bsontype: 'Timestamp', low_: 1, high_: 1579375735 } }
我预计它只检查 10 个键,但它正在检查 911 个键,我注意到
如果我通过不同的 _id 获取,则 totalKeysExamined
更改取决于 _id 位置(如果它来自)
最后插入的文档,数量较低,如果是来自第一个文档,则数量
很大
这是我数据库中的示例文档
{
"_id" : ObjectId("5e206f6f47fafc6b7fa32d0a"),
"txid" : "33deab70007a4210b2545f1ad516319bdedbcc836faf777c4af27431eab37c6d",
"size" : 134,
"vsize" : 134,
"locktime" : 0,
"weight" : null,
"version" : 1,
"vin" : [
{
"coinbase" : true
}
],
"vout" : [
{
"value" : 50,
"n" : 0,
"address" : "LMUZF47ySkrJ1njBRdQDyPVKkicziiZdQd",
"spent" : false,
"spent_ids" : []
}
],
"blocknumber" : 37,
"time" : 1318474943
}
最佳答案
Mongo 的索引以 b-tree
形式构建,如 this 中所述。视频。
我们无法真正知道树是如何构建的,但索引查询不太可能只检查 x
所需的文档(因为这需要所有这些文档都位于上层树中)水平)。
您从未提到过您的集合的规模,但是检查 900 个索引(或者用技术术语来说,迭代估计的 200 个树 Node )似乎并不是不合理。
您对基于_id
检查的文档的观察证实,一定范围会使树遍历更短,从而使mongo检查更少的文档。在一个非常简单的示例中,假设我们正在根据 _id
获取一个文档,如果文档 _id
在我们的 b-tree
根中建立了索引将检查单个文档,如果它位于其叶 Node 之一,我们将根据树的深度检查更多内容。
关于node.js - MongoDB 检查索引集合上的键太多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59804120/