admin管理员组

文章数量:1028473

MongoDB中的隐藏索引

官方文档:.0/core/index-hidden/

从MongoDB5.0开始引入了隐藏索引这个特性

隐藏索引对查询规划器不可见,且不能用于支持查询。

使用场景:

通过向规划器隐藏索引,您可以评估在不实际删除索引的情况下删除索引的潜在影响。如有不利影响,您可以取消隐藏该索引,而不必重新创建删除的索引。

行为

  1. 除了对规划器隐藏之外,隐藏索引的行为与未隐藏索引相同。例如:
    1. 如果隐藏索引是唯一索引,则该索引仍将其唯一约束应用于文档。
    2. 如果隐藏索引是 TTL 索引,该索引仍会使文档过期。
    3. 隐藏的索引包含在 listIndexes 和 db.collection.getIndexes() 结果中。
    4. 隐藏索引在对集合执行写入操作时进行更新,并继续消耗磁盘空间和内存。因此,它们包含在各种统计操作中,例如 db.collection.stats() 和 $indexStats。
    5. 隐藏未隐藏索引或取消隐藏索引都会重置其 $indexStats。隐藏已隐藏的索引或取消隐藏已取消隐藏的索引不会重置 $indexStats。

限制

  1. 要隐藏索引,必须将 featureCompatibilityVersion 设置为 5.0 或更大。
  2. 您无法隐藏 _id 索引。
  3. 不能 cursor.hint() 隐藏的索引。

实验

代码语言:txt复制
插入测试数据
rs01 [direct: primary] test> db.addresses.insertOne({"borough":"abcd"})
rs01 [direct: primary] test> db.addresses.insertOne({"borough":"defg"})
rs01 [direct: primary] test> db.addresses.find()
[
  { _id: ObjectId('680c6e3818c8de83cf964033'), borough: 'abcd' },
  { _id: ObjectId('680c6e3e18c8de83cf964034'), borough: 'defg' }
]

创建一个隐藏索引
rs01 [direct: primary] test> db.addresses.createIndex(
	{ borough: 1 },
	{ hidden: true }
 );


查看索引清单
rs01 [direct: primary] test> db.addresses.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { borough: 1 }, name: 'borough_1', hidden: true }
]


查询测试
rs01 [direct: primary] test> db.addresses.find({"borough":"abcd"}).explain()['queryPlanner']['winningPlan']
{
  stage: 'COLLSCAN',
  filter: { borough: { '$eq': 'abcd' } },
  direction: 'forward'
}

取消索引的hidden属性
rs01 [direct: primary] test> db.addresses.unhideIndex( "borough_1" );
{
  hidden_old: true,
  hidden_new: false,
  ok: 1,
  '$clusterTime': {
	clusterTime: Timestamp({ t: 1745644936, i: 1 }),
	signature: {
	  hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
	  keyId: Long('0')
	}
  },
  operationTime: Timestamp({ t: 1745644936, i: 1 })
}

查看索引清单
rs01 [direct: primary] test> db.addresses.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { borough: 1 }, name: 'borough_1' }
]

再次查询测试
rs01 [direct: primary] test> db.addresses.find({"borough":"abcd"}).explain()['queryPlanner']['winningPlan']
{
  stage: 'FETCH',
  inputStage: {
	stage: 'IXSCAN',
	keyPattern: { borough: 1 },
	indexName: 'borough_1',
	isMultiKey: false,
	multiKeyPaths: { borough: [] },
	isUnique: false,
	isSparse: false,
	isPartial: false,
	indexVersion: 2,
	direction: 'forward',
	indexBounds: { borough: [ '["abcd", "abcd"]' ] }
  }
}

可以看到执行计划变成了 IXSCAN 可以利用到索引了。


TIPS: 
隐藏一个索引,可以使用索引名的写法,也可以使用具体的列的写法:
	db.restaurants.hideIndex( { borough: 1, ratings: 1 } ); // Specify the index key specification document  列出相关列的写法
	db.restaurants.hideIndex( "borough_1_ratings_1" );  // Specify the index name  指定索引名的写法

对于一个已存在的索引,将它改为hidden属性。
	db.addresses.hideIndex( "borough_1" );  或者 db.addresses.hideIndex( { borough: 1 } );

MongoDB中的隐藏索引

官方文档:.0/core/index-hidden/

从MongoDB5.0开始引入了隐藏索引这个特性

隐藏索引对查询规划器不可见,且不能用于支持查询。

使用场景:

通过向规划器隐藏索引,您可以评估在不实际删除索引的情况下删除索引的潜在影响。如有不利影响,您可以取消隐藏该索引,而不必重新创建删除的索引。

行为

  1. 除了对规划器隐藏之外,隐藏索引的行为与未隐藏索引相同。例如:
    1. 如果隐藏索引是唯一索引,则该索引仍将其唯一约束应用于文档。
    2. 如果隐藏索引是 TTL 索引,该索引仍会使文档过期。
    3. 隐藏的索引包含在 listIndexes 和 db.collection.getIndexes() 结果中。
    4. 隐藏索引在对集合执行写入操作时进行更新,并继续消耗磁盘空间和内存。因此,它们包含在各种统计操作中,例如 db.collection.stats() 和 $indexStats。
    5. 隐藏未隐藏索引或取消隐藏索引都会重置其 $indexStats。隐藏已隐藏的索引或取消隐藏已取消隐藏的索引不会重置 $indexStats。

限制

  1. 要隐藏索引,必须将 featureCompatibilityVersion 设置为 5.0 或更大。
  2. 您无法隐藏 _id 索引。
  3. 不能 cursor.hint() 隐藏的索引。

实验

代码语言:txt复制
插入测试数据
rs01 [direct: primary] test> db.addresses.insertOne({"borough":"abcd"})
rs01 [direct: primary] test> db.addresses.insertOne({"borough":"defg"})
rs01 [direct: primary] test> db.addresses.find()
[
  { _id: ObjectId('680c6e3818c8de83cf964033'), borough: 'abcd' },
  { _id: ObjectId('680c6e3e18c8de83cf964034'), borough: 'defg' }
]

创建一个隐藏索引
rs01 [direct: primary] test> db.addresses.createIndex(
	{ borough: 1 },
	{ hidden: true }
 );


查看索引清单
rs01 [direct: primary] test> db.addresses.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { borough: 1 }, name: 'borough_1', hidden: true }
]


查询测试
rs01 [direct: primary] test> db.addresses.find({"borough":"abcd"}).explain()['queryPlanner']['winningPlan']
{
  stage: 'COLLSCAN',
  filter: { borough: { '$eq': 'abcd' } },
  direction: 'forward'
}

取消索引的hidden属性
rs01 [direct: primary] test> db.addresses.unhideIndex( "borough_1" );
{
  hidden_old: true,
  hidden_new: false,
  ok: 1,
  '$clusterTime': {
	clusterTime: Timestamp({ t: 1745644936, i: 1 }),
	signature: {
	  hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
	  keyId: Long('0')
	}
  },
  operationTime: Timestamp({ t: 1745644936, i: 1 })
}

查看索引清单
rs01 [direct: primary] test> db.addresses.getIndexes()
[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { borough: 1 }, name: 'borough_1' }
]

再次查询测试
rs01 [direct: primary] test> db.addresses.find({"borough":"abcd"}).explain()['queryPlanner']['winningPlan']
{
  stage: 'FETCH',
  inputStage: {
	stage: 'IXSCAN',
	keyPattern: { borough: 1 },
	indexName: 'borough_1',
	isMultiKey: false,
	multiKeyPaths: { borough: [] },
	isUnique: false,
	isSparse: false,
	isPartial: false,
	indexVersion: 2,
	direction: 'forward',
	indexBounds: { borough: [ '["abcd", "abcd"]' ] }
  }
}

可以看到执行计划变成了 IXSCAN 可以利用到索引了。


TIPS: 
隐藏一个索引,可以使用索引名的写法,也可以使用具体的列的写法:
	db.restaurants.hideIndex( { borough: 1, ratings: 1 } ); // Specify the index key specification document  列出相关列的写法
	db.restaurants.hideIndex( "borough_1_ratings_1" );  // Specify the index name  指定索引名的写法

对于一个已存在的索引,将它改为hidden属性。
	db.addresses.hideIndex( "borough_1" );  或者 db.addresses.hideIndex( { borough: 1 } );

本文标签: MongoDB中的隐藏索引