## 什么是索引 所有数据库都支持索引,索引文件通过额外占用磁盘空间,提供了一个快速查询记录的方案。查询时先查询索引文件,根据索引文件的指示再去查询真实的数据,在数据量较大时有明显的性能优势。 索引有两个用途: 1. 在集合中为查询条件的**字段**建立索引,是保证数据库性能、提升用户体验的重要手段。 2. 索引可以控制字段中各记录的唯一性。比如某字段被设为唯一索引,则这个字段在整个数据记录集合中的值不会有重复。如果是普通唯一索引,则意味着该字段不能为null。如果是稀疏索引,则代表可以为null,但不为null的值不能重复。 如果您的查询操作包含了过滤条件(包含等值测试和范围过滤)或者是排序功能,或者需要唯一性,则要考虑给集合的相关字段添加索引。通常来说需要为以下方法/属性内用到的**字段**添加索引`where、match、orderBy、sort`,还包括clientDB内`getTree`和`getTreePath`的`startWith属性`。 如果相关字段没有设为索引,当数据表的记录数量变大后,查询会变慢甚至超时报错。这点尤其需要注意。已经有一些开发者遭遇线上故障。开发时没有配索引,因为数据量小而没有性能问题。上线后数据量越来越大,查询越来越慢,直到超时,引发线上事故。 ## 添加索引 ### uniCloud web控制台添加 1. 进入 [uniCloud 控制台](https://console.cloud.tencent.com/tcb)。 2. 切换到【云数据库】标签页,并选择需要添加索引的集合,进入索引管理 tab 页,如下图。 ![web控制台添加索引](https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/15d24770-5faf-11eb-8d54-21c4ca4ce5d7.jpg) 3. 添加索引。 ![添加索引](https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/fca53140-1d91-11eb-880a-0db19f4f74bb.jpg) 注意: - 索引是支持多字段组合的,所以不是简单的设某个字段为索引。而是需要先给索引起一个name,然后在该索引下配置1个或多个字段。 - 索引字段的排序,指查询语句中的orderby的顺序。如果实际查询是需要倒叙,那么索引就设为倒叙,这样查询速度才能变快。 ### 在db_init.json内配置集合索引 在db_init.json内用如下写法可以给特定集合设置索引(推荐在服务空间初始化时使用) ```json { "opendb-news-article": { "data": [], "index":[{ "IndexName": "user_article_", // 索引名称 "MgoKeySchema": { // 索引规则 "MgoIndexKeys": [{ "Name": "user_id", // 索引字段 "Direction": "1" // 索引方向,1:ASC-升序,-1:DESC-降序,2dsphere:地理位置 },{ "Name": "article_id", // 索引字段 "Direction": "1" // 索引方向,1:ASC-升序,-1:DESC-降序,2dsphere:地理位置 }], "MgoIsUnique": false // 索引是否唯一 } }] } } ``` ## 单字段索引 您可以为查询条件对应的字段创建单字段索引,如果该字段是嵌套字段,可以使用"点表示法" 。例如对如下格式的记录中的`color`字段进行索引时,可以用`style.color`表示。 ```json { "_id": "", "style": { "color": "" } } ``` 在设置单字段索引时,可任意指定索引的排序为升序或降序,数据库总能在对索引字段的排序查询中,进行正确的排序。 ## 组合索引 组合索引即一个索引包含多个字段。当查询条件使用的字段包含在索引定义的所有字段或前缀字段里时,会命中索引,优化查询性能。 > 索引前缀即组合索引的字段中定义的前 1 到多个字段,例如对集合 **students** 中 **name**, **age**, **score** 三个字段按顺序定义了组合索引,那么该索引的前缀包含 > > - **name** > - **name, age** > > 能命中索引的查询字段组合包含 > > - **name** > - **name, age** > - **name, age, score** > ```json { "_id": "1", "name": "luke", "age": 26, "score": 80 } ``` 组合索引具有以下特点: 1. **字段顺序决定组合索引效果** 例如定义组合索引分别为 **name, age** 与 **age, name** 是不同的。当组合索引为 **name, age** 时,其索引前缀为 **name**, 对字段 **name** 的查询可以命中 **name, age** 索引, 而对字段 **age** 的查询无法命中该索引,因为 **age** 不属于 **name, age** 的前缀(反之字段 **age** 能命中 **age, name** 索引)。 2. **查询字段排序影响命中索引** 组合索引为 **age: 升序, score: 降序**,字段排序对索引命中效果如下: | **age: 升序, score: 降序** | **age: 降序, score: 升序** | **age: 升序, score: 升序** | **age: 降序, score: 降序** | **score: 升序/降序, age: 升序/降序** | | -------------------------- | -------------------------- | -------------------------- | -------------------------- | ------------------------------------ | | 命中 | 命中 | 未命中 | 未命中 | 未命中 | 组合索引为 **age: 升序, score: 升序**,字段排序对索引命中效果如下: | **age: 升序, score: 升序** | **age: 降序, score: 降序** | **age: 升序, score: 降序** | **age: 降序, score: 升序** | **score: 升序/降序, age: 升序/降序** | | -------------------------- | -------------------------- | -------------------------- | -------------------------- | ------------------------------------ | | 命中 | 命中 | 未命中 | 未命中 | 未命中 | **说明** - 未进行排序的字段设置正序倒序均可。 - 排序字段内存在索引不存在的情况下不会命中索引,例:组合索引为 **age: 升序, score: 升序**,使用`age、score、name`三个字段进行排序不会使用上述组合索引。 ### 地理位置索引 云数据库目前支持建立平面几何的地理位置索引,使用地理位置查询功能时,必须为地理位置数据的字段建立地理位置索引。 例如对含地理位置字段 **point** 的集合建立地理位置索引: ```json { "_id": "", "point": new db.Geo.Point(50, 50) } ``` ![地理位置索引](https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/21b31780-5fb0-11eb-bdc1-8bd33eb6adaa.jpg) ### TTL索引@ttl ttl索引用于设置数据过期时间,并在数据过期后进行删除。 配置方式如下: ![](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-f184e7c3-1912-41b2-b81f-435d1b37c7b4/25187fa4-dc40-48a2-ba00-e6ad8c604c39.jpg) **注意** - 数据删除并非实时,mongoDB会在后台定时进行数据清理 - 启用ttl索引后仅可添加一个索引字段 - 仅支持对存储了日期类型(并非时间戳)的字段进行设置ttl索引 ## 索引使用注意事项 ### 唯一性限制 创建索引时,索引属性选择**唯一**,即可添加唯一性限制。此限制会要求集合中**索引字段对应的值不能重复**。 例如,某个集合内建立了索引字段 `foo`,且属性为“唯一”,那么在这个集合内,要求不能存在 `foo` 字段相同的文档。 **注意** 假如**记录中不存在某个字段,则对索引字段来说其值默认为 null**。如果索引有唯一性限制,则不允许存在两个或以上的该字段为空 / 不存在该字段的记录。 针对上述问题,阿里云支持将索引设置为[稀疏索引](uniCloud/db-index.md?id=sparse),腾讯云暂不支持稀疏索引。 ### 稀疏索引@sparse > 仅阿里云支持 稀疏索引适用于需要某个字段唯一,但是这个字段又可能为空的场景。以`uni-id-users`表为例,用户可能是通过邮箱注册、也可能是通过手机号注册,所以需要保证邮箱、手机号唯一且允许为空,这时候就可以分别将邮箱、手机号的索引设置为稀疏索引来处理这种场景。 **配置索引为稀疏索引** ![](https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-dc-site/daf77fd0-5fb3-11eb-b680-7980c8a877b8.jpg) ### 字段大小限制 - 索引字段的值大小限制**不能超过 1024 字节**。 - 添加索引时,如果集合中已有文档索引字段内容超过 1024 字节,添加索引时将报错。 - 已设置索引的字段,如果插入一个文档,文档中该字段内容超过 1024 字节将会报错。 **即不要对大段的文字(例如新闻的内容)设置索引** > 每个英文字母(不分大小写)占一字节的空间,每个中文汉字占两字节的空间。 ### 正则表达式 正则查询无法使用索引提升性能。