数据模型与查询语言

Data Models and Query Languages

数据是以什么方式被人理解和使用的?

业务 - 数据模型 - 存储引擎

你 - 以什么方式 - 描述世界

数据模型

关系模型

命令式和声明式的区别

--ABAPAdaApacheApexBashBasicBatchCCMakeCOBOLC++C#CSSDartDiffDjangoErlangFortranGDScriptGoGroovyHaskellHLSLHTMLHTTPJavaJavaScriptJSONJSXJuliaKotlinLaTeXLessLispLuaMakefileMarkdownMATLABNginxObjective-CPascalPerlPHPPowerShellPropertiesPythonRRubyRustScalaSCSSShellSQLSwiftTCLTSXTypeScriptVB.NETVerilogVisual BasicXMLYAML

# 命令式
for(...) {
	if (...) {
	  ...
	}
}

# 声明式
select * from table where column > 10;

关系模型的优势:数据独立性

  • 表结构可以改、索引可以改、存储引擎可以换

例外:NoSQL

如果对象-关系不匹配,怎么处理?

例如:

--ABAPAdaApacheApexBashBasicBatchCCMakeCOBOLC++C#CSSDartDiffDjangoErlangFortranGDScriptGoGroovyHaskellHLSLHTMLHTTPJavaJavaScriptJSONJSXJuliaKotlinLaTeXLessLispLuaMakefileMarkdownMATLABNginxObjective-CPascalPerlPHPPowerShellPropertiesPythonRRubyRustScalaSCSSShellSQLSwiftTCLTSXTypeScriptVB.NETVerilogVisual BasicXMLYAML

Class user {
	Long id;
	String name;
	List<Address> addresses;
}
// 数据库中user和address都是单独的俩张表
// 此时就需要join,外键开始复杂映射
以下模型可以解决

文档模型

Document Model : MongoDB, CounchDB

核心思想: 一个“对象”,整体存一个文档(JSON)

文档模型的优势:

  • 结构灵活

  • 读写简单对象舒适

  • 适合用户信息、配置、日志

劣势:

  • 跨文档关联弱

  • 复杂查询困难

  • 数据一致性困难

图数据模型

当出现以下交互:

人 & 人; 用户 & 商品; 玩家 & 玩家(好友,工会,交易)

图数据模型的核心是:

  • 节点

  • 属性

代表数据库: Neo4j,图数据库

总结: 数据模型 = 思维方式

  • 强一致性,强约束性, 复杂查询 -- 关系模型

  • 本地聚合,灵活结构 -- 文档模型

  • 关系优先 -- 图模型

示例:

以用户系统出发

首先从现实出发:现实一个用户= 基本信息(id,名称,手机号)+多个登录方式(密码,微信,邮箱)+ 多个地址 + 状态(正常/封禁) + 产生行为(登录,下单)

抽象出来就是: 对象 + 子对象 + 关系

--ABAPAdaApacheApexBashBasicBatchCCMakeCOBOLC++C#CSSDartDiffDjangoErlangFortranGDScriptGoGroovyHaskellHLSLHTMLHTTPJavaJavaScriptJSONJSXJuliaKotlinLaTeXLessLispLuaMakefileMarkdownMATLABNginxObjective-CPascalPerlPHPPowerShellPropertiesPythonRRubyRustScalaSCSSShellSQLSwiftTCLTSXTypeScriptVB.NETVerilogVisual BasicXMLYAML

# 表结构+ 查询语句
user
- id 
- nickname
- status
- created_at

user_auth
- id
- user_id 
- type (password / wechat / email)
- identifier
- credential

user_address
- id
- user_id 
- province
- city

SELECT u.*, a.*
FROM user u
JOIN user_address a ON u.id = a.user_id
WHERE u.id = ?

关系模型

使用关系模型去表达:

好处:

1、外键,索引等约束十分清晰

2、查询能力很强:查询某个城市的用户等等

3、新增字段新增表不会乱原来的数据

代价:

1、表多

2、join多

3、ORM映射复杂

4、性能全靠索引和查询

文档模型创建用户

--ABAPAdaApacheApexBashBasicBatchCCMakeCOBOLC++C#CSSDartDiffDjangoErlangFortranGDScriptGoGroovyHaskellHLSLHTMLHTTPJavaJavaScriptJSONJSXJuliaKotlinLaTeXLessLispLuaMakefileMarkdownMATLABNginxObjective-CPascalPerlPHPPowerShellPropertiesPythonRRubyRustScalaSCSSShellSQLSwiftTCLTSXTypeScriptVB.NETVerilogVisual BasicXMLYAML

{
  "_id": 123,
  "nickname": "Tom",
  "status": "NORMAL",
  "auth": [
    { "type": "password", "hash": "xxx" },
    { "type": "wechat", "openid": "ooo" }
  ],
  "addresses": [
    { "city": "Guangzhou" },
    { "city": "Changsha" }
  ]
}
  • 一个用户只需要查询一次,所有信息都可以得到

问题:

1、 唯一性验证如何做,例如id不重复,手机号不重复等?

  • 加索引,跨字段和嵌套数组开始复杂

2、 用户修改了地址,订单的地址怎么办

  • 地址同步维护如何进行

3、 批量查询

  • 查询广州用户 等

总结:文档模型不适合复杂关系的存取,更为适合“聚合读取”

聚合读取: 一组必须**“一起被读取,一起被修改”**的数据

查询能力 > 写入舒服

查询语言 = 思维能力的上界

作者:查询语言决定了你能多聪明的使用数据

接下来通过对比学习加深理解

声明式查询对比命令式查询

--ABAPAdaApacheApexBashBasicBatchCCMakeCOBOLC++C#CSSDartDiffDjangoErlangFortranGDScriptGoGroovyHaskellHLSLHTMLHTTPJavaJavaScriptJSONJSXJuliaKotlinLaTeXLessLispLuaMakefileMarkdownMATLABNginxObjective-CPascalPerlPHPPowerShellPropertiesPythonRRubyRustScalaSCSSShellSQLSwiftTCLTSXTypeScriptVB.NETVerilogVisual BasicXMLYAML

# 命令式
for (User u : users) {
  if (u.getAge() > 18) {
    result.add(u);
  }
}

# 声明式
SELECT * FROM user WHERE age > 18;

  • 命令式: 定义步骤及步骤行为

  • 声明式: 只声明要什么,不说具体如何获取,系统自由选方案

从以上对比来说:

声明式

  • 抽象程度更高,只需要表达目标

  • 解耦

  • 适合并行和分布式,给了系统优化空间(cpu增加,硬件增加,并行能力更高)

例如:

MapReduce(hadoop):

--ABAPAdaApacheApexBashBasicBatchCCMakeCOBOLC++C#CSSDartDiffDjangoErlangFortranGDScriptGoGroovyHaskellHLSLHTMLHTTPJavaJavaScriptJSONJSXJuliaKotlinLaTeXLessLispLuaMakefileMarkdownMATLABNginxObjective-CPascalPerlPHPPowerShellPropertiesPythonRRubyRustScalaSCSSShellSQLSwiftTCLTSXTypeScriptVB.NETVerilogVisual BasicXMLYAML

map(key, value) → list(key2, value2)
reduce(key2, list(value2)) → result

指定了目标,数据如何流,中间结构,管理执行逻辑

但是

作者声明: 写的出来跑得快 更重要

性能可以优化,但是表达能力没法快速解决

例如: 查询30天活跃但未下单用户,查询多个登录方式但是未修改密码的用户等

因此,作者观点:没有明确知道要选什么,关系模型更为安全