db-index.md 8.7 KB
Newer Older
Q
qiang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
## 什么是索引

所有数据库都支持索引,索引文件通过额外占用磁盘空间,提供了一个快速查询记录的方案。查询时先查询索引文件,根据索引文件的指示再去查询真实的数据,在数据量较大时有明显的性能优势。

索引有两个用途:

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 字节将会报错。

**即不要对大段的文字(例如新闻的内容)设置索引**

> 每个英文字母(不分大小写)占一字节的空间,每个中文汉字占两字节的空间。

### 正则表达式

正则查询无法使用索引提升性能。