MongoDB 高级索引

考虑以下文档集合(users ):

{
   "address": {
      "city": "Los Angeles",
      "state": "California",
      "pincode": "123"
   },
   "tags": [
      "music",
      "cricket",
      "blogs"
   ],
   "name": "Tom Benzamin"
}

以上文档包含了 address 子文档和 tags 数组。


索引数组字段

假设我们基于标签来检索用户,为此我们需要对集合中的数组 tags 建立索引。

在数组中创建索引,需要对数组中的每个字段依次建立索引。所以在我们为数组 tags 创建索引时,会为 music、cricket、blogs三个值建立单独的索引。

使用以下命令创建数组索引:

>db.users.ensureIndex({"tags":1})

创建索引后,我们可以这样检索集合的 tags 字段:

>db.users.find({tags:"cricket"})

为了验证我们使用使用了索引,可以使用 explain 命令:

>db.users.find({tags:"cricket"}).explain()

以上命令执行结果中会显示 "cursor" : "BtreeCursor tags_1" ,则表示已经使用了索引。


索引子文档字段

假设我们需要通过city、state、pincode字段来检索文档,由于这些字段是子文档的字段,所以我们需要对子文档建立索引。

为子文档的三个字段创建索引,命令如下:

>db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})

一旦创建索引,我们可以使用子文档的字段来检索数据:

>db.users.find({"address.city":"Los Angeles"})   

查询表达不一定遵循指定的索引的顺序,mongodb 会自动优化。所以上面创建的索引将支持以下查询:

>db.users.find({"address.state":"California","address.city":"Los Angeles"}) 

同样支持以下查询:

>db.users.find({"address.city":"Los Angeles","address.state":"California","address.pincode":"123"})
<think> 我们正在讨论MongoDB的TTL索引。根据引用的内容,我们可以总结TTL索引的配置和使用方法。以下将按照用户需求,详细介绍TTL索引的配置、使用、注意事项以及最佳实践。 ### 一、TTL索引概述 TTL索引(Time To Live Index)是MongoDB中一种特殊的单字段索引,用于自动删除集合中的过期文档。它通过为文档设置一个生存时间,当文档超过指定的时间后,MongoDB会自动将其删除。这种机制常用于日志记录、临时会话存储等需要自动清理的场景。 ### 二、TTL索引的配置 #### 1. 创建TTL索引 创建TTL索引的语法如下: ```javascript db.collection.createIndex({ "dateField": 1 }, { expireAfterSeconds: 3600 }) ``` - `dateField`:必须是日期类型(Date)的字段,用于计算文档的过期时间。 - `expireAfterSeconds`:文档的存活时间(秒),从`dateField`指定的时间开始计算。 **示例**:创建一个在`lastModifiedDate`字段上的TTL索引,文档在1小时后过期: ```javascript db.log_events.createIndex({ "lastModifiedDate": 1 }, { expireAfterSeconds: 3600 }) ``` #### 2. 修改TTL索引的过期时间 修改已存在的TTL索引的过期时间,可以使用`collMod`命令: ```javascript db.runCommand({ "collMod": "collection_name", "index": { "keyPattern": { "dateField": 1 }, "expireAfterSeconds": 7200 // 修改为2小时 } }) ``` **注意**:不能直接修改索引的`expireAfterSeconds`属性,必须先删除索引再重建,但使用`collMod`可以避免重建索引的开销(引用[4])[^4]。 ### 三、TTL索引的工作原理 - MongoDB后台有一个线程(TTL monitor)每隔**60秒**运行一次,检查并删除过期的文档。 - 删除操作可能存在延迟,因此文档的实际存活时间可能比设定的时间稍长(引用[4])[^4]。 - 在副本集中,TTL线程仅在主节点(Primary)运行,从节点(Secondary)通过复制主节点的删除操作来同步(引用[4])[^4]。 ### 四、TTL索引的使用约束 1. **字段类型限制**:TTL索引只能应用于**日期类型**的字段。如果字段不是日期类型,或者文档中不包含该字段,则文档不会过期(引用[4])[^4]。 2. **不支持复合索引**:TTL索引只能是单字段索引,不能是复合索引(引用[4])[^4]。 3. **固定集合(capped collection)**:不支持TTL索引(引用[4])[^4]。 4. **_id字段**:不能创建TTL索引(引用[4])[^4]。 5. **修改限制**:不能使用`createIndex()`修改已存在的TTL索引的`expireAfterSeconds`属性,必须使用`collMod`命令或删除后重建(引用[4])[^4]。 ### 五、高级用法:指定具体的过期时间 除了设置相对过期时间(如1小时),还可以通过存储**具体的过期时间点**来实现精确控制。例如: ```javascript // 插入文档时指定expireAt为具体的过期时间 db.log_events.insert({ "log": "event", "expireAt": new Date("2023-12-31T23:59:59Z") // 文档将在该时间点过期 }) // 创建TTL索引,并将expireAfterSeconds设为0 db.log_events.createIndex({ "expireAt": 1 }, { expireAfterSeconds: 0 }) ``` 这样,文档会在`expireAt`指定的确切时间被删除(引用[2])[^2]。 ### 六、操作验证 1. **查看索引状态**: ```javascript db.collection.getIndexes() ``` 2. **检查过期文档**: ```javascript // 手动触发TTL线程(仅用于测试) db.adminCommand({ "runCommand": 1, "command": "touch", "data": "/var/lib/mongodb" }) ``` ### 七、最佳实践 1. **选择高写入性能的硬件**:TTL删除操作会增加I/O负载(引用[2])[^2]。 2. **避免频繁更新**:频繁更新带TTL索引的字段会导致索引重排,影响性能(引用[4])[^4]。 3. **监控删除延迟**:通过日志监控TTL线程的运行状态,确保删除延迟在可接受范围内(引用[4])[^4]。 --- ### 示例场景 **场景:用户会话管理** ```javascript // 创建会话集合 db.sessions.createIndex({ "lastAccessTime": 1 }, { expireAfterSeconds: 86400 }) // 24小时后过期 // 插入新会话 db.sessions.insert({ "userId": 123, "data": { ... }, "lastAccessTime": new Date() // 从当前时间开始计算24小时 }) ``` --- §§相关问题§§ 1. TTL索引删除操作的延迟如何监控和优化? 2. 如何为不同文档设置动态的TTL时间? 3. TTL索引与手动删除文档的性能对比? 4. TTL索引在分片集群中的工作方式? 5. 是否存在替代TTL索引的数据清理方案? [^1]: MongoDB TTL索引概述 [引用1] [^2]: TTL索引高级用法 [引用2] [^3]: Java驱动中TTL索引注解 [引用3] [^4]: TTL索引运行机制与限制 [引用4] </think> ### MongoDB TTL索引配置与使用详解 TTL(Time To Live)索引MongoDB的自动过期数据管理机制,以下是关键配置步骤和使用要点(基于引用[1][^1][^2][^3][^4]): --- #### **一、配置方法** 1. **基础语法** ```javascript // 在日期字段上创建TTL索引(单位:秒) db.collection.createIndex({ "expireAt": 1 }, { expireAfterSeconds: 3600 }) // 1小时后过期[^1][^4] ``` 2. **精确时间点过期** ```javascript // 文档插入时指定具体过期时间点 db.logs.insert({ message: "Error", expireAt: new Date("2023-12-31T23:59:59Z") // 指定绝对时间 }) // 索引配置为0秒过期(依赖expireAt字段值) db.logs.createIndex({ "expireAt": 1 }, { expireAfterSeconds: 0 })[^2] ``` 3. **Java驱动配置示例** ```java @Document(collection = "sessions") public class UserSession { @Indexed(expireAfterSeconds = 1800) // 30分钟后过期 private Date lastActiveTime; }[^3] ``` --- #### **二、核心运行机制** 1. **后台清理线程** - 每 **60秒** 扫描一次TTL索引[^4] - 实际删除时间可能存在延迟(如下图): $$ \text{设定过期时间} + \text{60秒} \leq \text{实际删除时间} $$ 2. **副本集行为** - 仅在Primary节点执行删除操作 - Secondary节点通过oplog同步删除[^4] --- #### **三、使用约束与注意事项** | **限制项** | **说明** | |--------------------------|-------------------------------------------------------------------------| | **字段类型** | 必须是Date类型,否则索引无效[^4] | | **复合索引** | 不支持TTL属性(只能单字段)[^4] | | **_id字段** | 禁止创建TTL索引[^4] | | **固定集合** | 不支持TTL(capped collection)[^4] | | **文档字段缺失** | 缺少索引字段的文档永不过期[^4] | | **索引修改** | 必须通过`collMod`命令或重建索引修改`expireAfterSeconds`[^4] | ```javascript // 修改TTL过期时间示例 db.runCommand({ collMod: "logs", index: { keyPattern: { expireAt: 1 }, expireAfterSeconds: 86400 } })[^1][^4] ``` --- #### **四、最佳实践** 1. **选择高精度时间字段** - 优先选用ISODate类型的时间戳字段 - 避免使用低精度时间(如仅存储到"天") 2. **延迟删除应对策略** ```javascript // 设置比实际需求更短的过期时间(预留60秒缓冲) db.events.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3540 }) // 59分钟 ``` 3. **监控删除状态** ```bash mongod --setParameter ttlMonitorSleepSecs=30 # 调整扫描间隔(默认60秒)[^4] ``` 查看日志关键词:`[TTLMonitor]` --- #### **五、典型应用场景** 1. **会话管理** ```javascript // 用户会话30分钟过期 db.sessions.createIndex({ lastActive: 1 }, { expireAfterSeconds: 1800 }) ``` 2. **临时存储** - 验证码(5分钟过期) - 临时文件元数据 3. **日志轮转** ```javascript // 保留7天日志 db.nginx_logs.createIndex({ timestamp: 1 }, { expireAfterSeconds: 604800 }) ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值