# 数据建模方法

> 本文档重要讨论在接收到一个需求后，应如何进行数据建模流程，重点在于归纳一些建模方法。

## 前置资料

本文档基于已阅读以下文档的前提下进行讨论，如果尚未阅读以下文档，可以先阅读浏览。

- [模型设计基础](数据建模-模型设计基础.md)
- [JSON文档模型设计特点](数据建模-JSON文档模型设计特点.md)

![数据建模方法提纲](../img/data-thinking/数据建模方法.jpg)

## 数据建模流程概述

传统模型的**建模顺序**：`概念模型` -> `逻辑模型` -> `物理模型`

|            | 概念模型 `CDM`                                     | 逻辑模型 `LDM`                                   | 物理模型 `PDM`                                               |
| ---------- | -------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------ |
| 目的       | 描述业务系统要管理的对象                           | 基于概念模型，详细列出所有实体，实体的属性及关系 | 根据逻辑模型，结合数据库的物理结构，设计具体的表结构，字段列表及主外键 |
| 特点       | 用概念名词来描述现实中的实体及业务规则，如'联系人' | 基于业务的描述和数据库无关                       | 技术实现细节和具体的数据库类型相关                           |
| 主要使用者 | 用户<br />需求分析师                               | 需求分析师<br />架构师及开发者                   | 开发者<br />`DBA`                                            |

- 第一步，`概念模型`：是抽象的，描述业务的对象，这一层很模糊。
- 第二步，`逻辑模型`：就是将概念模型实体化，具体到这个业务有哪几个对象，每个对象有什么属性，对象与对象之间的关系。
- 第三步，`物理模型`：就是基于具体的物理数据库结构，将逻辑模型进一步细化。根据**业务特点**，**性能要求**选择合适的数据建模方法。

如果对`物理建模`等概念还不清晰的，可查看 [模型设计基础](数据建模-模型设计基础.md)。 我们在开发过程中， 更多的是关注`逻辑模型`、`物理模型`阶段。
现在我们在这个传统模型的建模顺序基础上，讨论我们的数据建模步骤：

## （重点）数据建模步骤
> 生产中数据建模的工作流程

1. 第一步，逻辑导向，整理出 `逻辑模型` 中的所有实体、属性和关系。

2. 第二步，技术导向，将第一步中的实体、属性和关系转换为基本的内嵌或引用结构，不考虑性能。

3. 第三步，工况导向，分析[数据建模考虑的工况](#（重点）数据建模考虑的工况)，选择合适的[建模方法](#（重点）建模方法)进行最终建模。

![数据建模流程](../img/data-thinking/数据建模流程.png)

## （重点）建模方法
> 适用于特定工程场景的设计模式

- **[内嵌](#1.内嵌)**
- **[引用](#2.引用)**
- **[分桶](#3.分桶)**
- **[列转行](#4.列转行)**
- **[近似计算](#5.近似计算)**
- **[预聚合](#6.预聚合)**

## （重点）数据建模考虑的工况
> 数据建模时，需要根据业务具体考虑的情况

- 最频繁的数据查询模式
- 最频繁的数据写入模式
- 读写操作的比例
- 最常用的查询参数
- 数据量的大小

## 应对策略

- 使用引用来避免性能瓶颈
- 使用冗余来优化访问性能
- 适用预聚合优化统计性能

> 上述是对本文档的一个概述，一个提纲。下文总结在接受一个需求后，如何选择一种建模方法。

## 建模方法详解

### 1.内嵌

**建模实现**：【使用冗余来优化访问性能】点击查看案例 [建模方法-内嵌](建模方法-内嵌.md)

**适用场景**：读多写少的情况。

**优势**：类似于预聚合，可以提高读取的速度。

**劣势**：更新数据时，需要扫库批量处理关联数据。需要更多的空间，数据量过大时，扫库更新会带来压力。

### 2.引用

**建模实现**：【使用引用来避免性能瓶颈】点击查看案例 [建模方法-引用](建模方法-引用.md)。

**适用场景**： 1）属性体积过大且读取频率低 2）数据量大且属性修改频繁。

**优势**：更新数据，无需额外更新关联数据，减少空间占用。

**劣势**：对于读多且连表数量过多的场景，容易造成性能瓶颈。

### 3.分桶

**建模实现**：点击查看案例 [建模方法-分桶](建模方法-分桶.md)

**适用场景**：数据采集频繁，数据量太多，且大多数查询是按分桶的属性为条件，如案例中的时间。

**优势**：大量减少文档数量，减少索引所占空间。

**劣势**：如果查询条件不是分桶的属性，则只能全表扫描，非分桶属性难以建立索引。

### 4.列转行

**建模实现**：点击查看案例 [建模方法-列转行](建模方法-列转行.md)

**适用场景**：有很多类似的字段用于组合查询搜索，需要建立很多索引，索引占用空间过大。

**优势**：一个索引解决所有查询问题。

**劣势**：非组合查询下，单个查询很难复用索引，需要全表扫描。

### 5.近似计算

**建模实现**：点击查看案例 [建模方法-近似计算](建模方法-近似计算.md)

**适用场景**：写入频繁且持续累加且不需要精确值的场景，模糊统计。

**优势**：大量减少写入需求

**劣势**：无法得到精确值，只能是一个估值。

### 6.预聚合

**建模实现**：点击查看案例 [建模方法-预聚合](建模方法-预聚合.md)

**适用场景**：写入太频繁，消耗系统资源，聚合计算时间长的统计类的场景。

**优势**：直接增加统计字段，每次更新数据的时候同时更新统计值，消除了聚合计算的过程。

**劣势**：聚合统计的字段需要维护。

## 总结

数据建模是一个循序渐进，根据业务灵活变化的过程。
 
![数据建模流程](../img/data-thinking/数据建模流程.png)

### 本文重点

**数据建模步骤**：

1. 第一步，逻辑导向，整理出 `逻辑模型` 中的所有实体、属性和关系。

2. 第二步，技术导向，将第一步中的实体、属性和关系转换为基本的内嵌或引用结构，不考虑性能。

3. 第三步，工况导向，分析[数据建模考虑的工况](#（重点）数据建模考虑的工况)，选择合适的[建模方法](#（重点）建模方法)进行最终建模。

**建模方法**：

- **[内嵌](#1.内嵌)**
- **[引用](#2.引用)**
- **[分桶](#3.分桶)**
- **[列转行](#4.列转行)**
- **[近似计算](#5.近似计算)**
- **[预聚合](#6.预聚合)**

**数据建模考虑的工况**：

- 最频繁的数据查询模式
  
- 最频繁的数据写入模式
  
- 读写操作的比例
  
- 最常用的查询参数
  
- 数据量的大小


