数据模型与查询语言
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天活跃但未下单用户,查询多个登录方式但是未修改密码的用户等
因此,作者观点:没有明确知道要选什么,关系模型更为安全