简短回答:是的。
长答案:它将如何影响查询取决于许多因素,例如查询的性质、可用内存和索引大小。
你能做的最好的就是测试。
下面的代码将生成两个名为 smallDocuments 和 bigDocuments 的集合,每个集合有 1024 个文档,不同之处仅在于包含大字符串和 _id 的字段“c”。 bigDocuments 集合大约有 2GB,因此请小心运行它。
const numberOfDocuments = 1024;
// 2MB string x 1024 ~ 2GB collection
const bigString = 'a'.repeat(2 * 1024 * 1024);
// generate and insert documents in two collections: shortDocuments and
// largeDocuments;
for (let i = 0; i < numberOfDocuments; i++) {
let doc = {};
// field a: integer between 0 and 10, equal in both collections;
doc.a = ~~(Math.random() * 10);
// field b: single character between a to j, equal in both collections;
doc.b = String.fromCharCode(97 + ~~(Math.random() * 10));
//insert in smallDocuments collection
db.smallDocuments.insert(doc);
// field c: big string, present only in bigDocuments collection;
doc.c = bigString;
//insert in bigDocuments collection
db.bigDocuments.insert(doc);
}
您可以将此代码放在一个文件中(例如 create-test-data.js)并直接在 mongoshell 中运行它,输入以下命令:
mongo testDb < create-test-data.js
这需要一段时间。之后,您可以执行一些测试查询,例如:
const numbersToQuery = [];
// generate 100 random numbers to query documents using field 'a':
for (let i = 0; i < 100; i++) {
numbersToQuery.push(~~(Math.random() * 10));
}
const smallStart = Date.now();
numbersToQuery.forEach(number => {
// query using inequality conditions: slower than equality
const docs = db.smallDocuments
.find({ a: { $ne: number } }, { a: 1, b: 1 })
.toArray();
});
print('Small:' + (Date.now() - smallStart) + ' ms');
const bigStart = Date.now();
numbersToQuery.forEach(number => {
// repeat the same queries in the bigDocuments collection; note that the big field 'c'
// is ommited in the projection
const docs = db.bigDocuments
.find({ a: { $ne: number } }, { a: 1, b: 1 })
.toArray();
});
print('Big: ' + (Date.now() - bigStart) + ' ms');
在这里我得到了以下结果:
无索引:
Small: 1976 ms
Big: 19835 ms
在两个集合中索引字段“a”后,使用.createIndex({ a: 1 }):
Small: 2258 ms
Big: 4761 ms
这表明对大文档的查询速度较慢。使用索引,bigDocuments 的结果时间比 smallDocuments 大 100% 以上。
我的建议是:
- 在查询中使用相等条件 (https://docs.mongodb.com/manual/core/query-optimization/index.html#query-selectivity);
- 使用覆盖查询 (https://docs.mongodb.com/manual/core/query-optimization/index.html#covered-query);
- 使用适合内存的索引 (https://docs.mongodb.com/manual/tutorial/ensure-indexes-fit-ram/);
- 保持文档小;
- 如果您需要使用文本索引的短语查询,请确保整个集合都适合内存(https://docs.mongodb.com/manual/core/index-text/#storage-requirements-and-performance-costs,最后一个项目符号);
- 生成测试数据并进行测试查询,模拟您的应用用例;如果需要,使用随机字符串生成器。
我在大文档中使用 MongoDB 进行文本查询时遇到问题:Autocomplete and text search memory issues in apostrophe-cms: need ideas
这里有一些我编写的用于在 ApostropheCMS 中生成示例数据的代码,以及一些测试结果:https://github.com/souzabrs/misc/tree/master/big-pieces。
这更像是一个数据库设计问题,而不是 MongoDB 内部问题。我认为 MongoDB 就是这样设计的。但是,在其文档中提供更明显的解释会大有帮助。