更新时间:2025-03-26 GMT+08:00
避免hideIndex导致游标失效
失效场景
在 DDS 中,某些索引操作可能导致游标失效,DDS这些行为和社区版MongoDB行为一致。以下是几个常见的例子及其解释:
hideIndex导致游标失效
原因:
hideIndex操作改变了索引的元数据,从而使现有游标失效。
示例代码:
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引,并插入数据,
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标,但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前隐藏索引
coll.hideIndex("x_1");
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错:
// "errmsg" : "definition of index 'x_1' changed"
// "codeName" : "QueryPlanKilled"
print(tojson(doc));
});
})();
结果:
游标失效,可能抛出错误。
2024-12-24T16:26:42.445+0800 E QUERY [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "definition of index 'x_1' changed",
"code" : 175,
"codeName" : "QueryPlanKilled"
} :
dropIndex 导致游标失效
原因:
删除索引后,DDS需要重新计算查询计划,从而使现有游标失效。
示例代码:
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引,并插入数据,
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标,但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前删除索引
coll.dropIndex("x_1");
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错:
// "errmsg" : "index 'x_1' dropped",
// "codeName" : "QueryPlanKilled"
print(tojson(doc));
});
})();
结果:
游标失效,因为删除索引会导致查询计划需要重新计算。
2024-12-25T10:34:29.948+0800 E QUERY [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "index 'x_1' dropped",
"code" : 175,
"codeName" : "QueryPlanKilled"
}
renameCollection导致游标失效
原因:
修改集合结构renameCollection也会导致游标失效。
示例代码:
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引,并插入数据,
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标,但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前重命名集合
coll.renameCollection("test_coll_reaname");
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错:
// "errmsg" : "collection dropped between getMore calls",
// "codeName" : "OperationFailed"
print(tojson(doc));
});
})();
结果:
游标失效,因为集合的名称改变,游标失去了上下文。
2024-12-25T10:39:28.624+0800 E QUERY [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "collection dropped between getMore calls",
"code" : 96,
"codeName" : "OperationFailed"
} :
dropCollection导致游标失效
原因:
删除集合游标失去了上下文,会导致游标失效。
示例代码:
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引,并插入数据,
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标,但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前删除集合
coll.drop();
// 遍历游标
cursor.forEach((doc) => {
// 游标会报错:
// "errmsg" : "collection dropped between getMore calls",
// "codeName" : "OperationFailed"
print(tojson(doc));
});
})();
结果:
游标失效,因为集合已经被删除,游标失去了上下文。
2024-12-25T10:40:33.737+0800 E QUERY [js] Error: getMore command failed: {
"ok" : 0,
"errmsg" : "collection dropped between getMore calls",
"code" : 96,
"codeName" : "OperationFailed"
} :
解决方法
- 在索引操作之前处理游标: 确保在 hideIndex 或 dropIndex 之前使用完游标。
- 重新获取游标: 如果索引发生变化,重新执行查询以获取新的游标。
- 提前计划: 避免在长时间查询中执行索引操作。
示例代码:
(function() {
"use strict";
let collName = "test_coll";
let coll = db.getCollection(collName);
coll.drop();
// 创建索引,并插入数据,
coll.createIndex({x: 1}, {background: false});
for (var i = 0; i < 1000; ++i) {
coll.insert({x: i});
}
// 获取游标
let cursor = coll.find({x: {$gte: 1}});
// 使用游标,但是游标并没有使用完
for (var i = 0; i < 101; ++i) {
let doc = cursor.next();
print(tojson(doc));
}
// 在游标使用完之前隐藏索引
coll.hideIndex("x_1");
// 遍历游标
// cursor.forEach((doc) => {
// 游标会报错:
// "errmsg" : "definition of index 'x_1' changed"
// "codeName" : "QueryPlanKilled"
// print(tojson(doc));
// });
// 重新获取游标
cursor = coll.find({x: {$gte: 1}});
cursor.forEach((doc) => {
print(tojson(doc));
});
})();