关系数据库应用设计基础

4,547 views
4,307 views

Published on

关系数据库应用设计基础

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,547
On SlideShare
0
From Embeds
0
Number of Embeds
1,609
Actions
Shares
0
Downloads
61
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

关系数据库应用设计基础

  1. 1. 关系数据库应用设计 基础 ideawu 百度客户端软件部后端组 http://www.ideawu.net/
  2. 2. 内容简介 <ul><li>以 MySQL 为平台 </li></ul><ul><li>关系数据库基础理论 </li></ul><ul><li>经典设计和用法 </li></ul><ul><li>常用 SQL 查询 </li></ul><ul><li>数据库优化 </li></ul><ul><li>本文的例子 – RSS 订阅器 </li></ul>
  3. 3. 理论结合实践 , 实践结合理论 <ul><li>“ 理论要结合实践” , 是对理论的贬低吗 ? </li></ul><ul><li>理论和实践 </li></ul><ul><ul><li>理论不结合实践 - 书呆子 </li></ul></ul><ul><ul><li>实践不结合理论 - 业余者 </li></ul></ul><ul><ul><li>理论结合实践 - 科学家 </li></ul></ul><ul><ul><li>实践结合理论 - 专业者 </li></ul></ul>阅读了 XX 源码的人 普通码农 一楼 掌握了理论的人 二楼 能进行理论创新的人 三楼
  4. 4. 常用工具 <ul><li>phpmyadmin </li></ul>
  5. 5. 实体关系模型 (ER) <ul><li>进行业务分析时 , 业务描述中的名词一般都可归结为”实体” (Entity) </li></ul><ul><ul><li>例 : 用户订阅了一个博客 . 归结出两个实体 : 用户 , 博客 </li></ul></ul><ul><li>业务描述中的动词一般都可归结为”关系” (Relation) </li></ul><ul><ul><li>接上例 : 一个关系 : 订阅 </li></ul></ul><ul><li>实体一般对应数据库表 , 关系对应外键和表 . </li></ul>
  6. 6. 数据库表和字段的命名规则 <ul><li>用户 (User) </li></ul><ul><ul><li>id, name, password </li></ul></ul><ul><li>博客 (Site) </li></ul><ul><ul><li>id, name, url </li></ul></ul><ul><li>经验和惯用法 </li></ul><ul><ul><li>第一个实体表都有一个自增 (auto_increment) 的整数字段作为主键 , 这个字段是不具有业务意义 , 名为 id, 不要带表名前缀 ( 如 user_id). </li></ul></ul><ul><ul><li>如果实体有唯一的属性可作为主键 ( 如员工号 ), 但还是应该设立一个 id 字段 , 同时把该属性加上 UNIQUE 索引 . </li></ul></ul><ul><ul><li>表名和字段名小写下划线 ( 强烈建议 !) </li></ul></ul>
  7. 7. 关系类型 <ul><li>一对一 (1:1) </li></ul><ul><ul><li>用户的基本信息是一个表 , 附加信息是另一个表 </li></ul></ul><ul><ul><li>共享主键关联 , 外键关联 </li></ul></ul><ul><li>一对多 (1:n) </li></ul><ul><ul><li>一个分类包含多篇文章 , 多篇文章属于一个分类 </li></ul></ul><ul><li>多对多 (m:n) </li></ul><ul><ul><li>一个 分类包含多篇文章 , 一篇 文章属于多个分类 </li></ul></ul>
  8. 8. 实体关系图 (ERD) <ul><li>实体 , 用矩形表示 </li></ul><ul><li>关系 , 用菱形和连线表示 , 非多对多时可省略菱形 , 连线两端标名” 1”, “m”, “n”, 当一端是” m” 时 , 连线的端点带分叉 </li></ul>
  9. 9. ER 图表示实体关系 <ul><li>一对一 </li></ul><ul><li>一对多 </li></ul><ul><li>多对多 </li></ul>
  10. 10. 实体和实体关系的表设计 <ul><li>一对一 </li></ul><ul><ul><li>共享主键 : user{id, name}, user_ext{id, other} </li></ul></ul><ul><ul><li>外键 : user{id, name}, user_ext{id, user_id, other}, 适用场景 : 比如最初是两个系统中的表 </li></ul></ul><ul><li>一对多 </li></ul><ul><ul><li>外键 : category{id, name}, item{id, category_id , title} </li></ul></ul><ul><li>多对多 </li></ul><ul><ul><li>后接 ...>> </li></ul></ul>
  11. 11. 实体和实体关系的表设计 ( 续 ) <ul><li>多对多 </li></ul><ul><ul><li>简单关联 : subscribe{user_id, site_id} </li></ul></ul><ul><ul><li>带附加属性的关联 : subscribe{ id , user_id, item_id, 订阅时间 } </li></ul></ul><ul><li>一旦关系带有附加属性 , 那么关系本身就是一个实体 , 最好带有无业务意义自增 id. </li></ul><ul><li>符合理论模型 , 多对多关系要使用 3 个表 . </li></ul>
  12. 12. 不符合理论模型的多对多关系设计 <ul><li>用两个表来表示多对多 </li></ul><ul><ul><li>user_subscribe{user_id, 逗号分隔的博客 id 列表 } </li></ul></ul><ul><li>“ 关系”被弱化 , 无法进行关系操作 </li></ul><ul><ul><li>不能这样获取订阅者列表 : select user_id from user_subscribe where item_id=1 </li></ul></ul><ul><ul><li>虽然可以在 SQL 查询中用字符串处理操作来达到目的 , 但不是关系操作 . </li></ul></ul><ul><li>这种做法叫”逆规范化” , 也即” 反细化 ” </li></ul><ul><ul><li>粒度越小 , 可操纵程度越高 , 但增加成本 . 反之 , 也有道理 . </li></ul></ul><ul><ul><li>退化成类似所谓的 KV </li></ul></ul><ul><ul><li>避免冗余 </li></ul></ul><ul><ul><li>某些操作 可能 提升性能 , 如获取用户的订阅博客 id 列表 </li></ul></ul><ul><ul><li>... </li></ul></ul>
  13. 13. 建立数据库和表
  14. 14. 字段类型的选择 <ul><li>主键 : id, INT/BIGINT, autoincrement, PK </li></ul><ul><li>外键 : 表名 _id, INT/BIGINT, KEY </li></ul><ul><li>短字段串 : VARCHAR/CHAR </li></ul><ul><li>长字段串 : TEXT/LONGTEXT </li></ul><ul><li>时间 : DATETIME, INT </li></ul><ul><li>二进制数据 : BLOB/LONGBLOB </li></ul><ul><li>唯一索引 : 如字段没有重复值 , 可加上 UNIQUE 索引 </li></ul>
  15. 15. 关系数据库经典用法和设计 <ul><li>树形结构在关系数据库中的存储 </li></ul><ul><ul><li>category{id, parent_id, name} </li></ul></ul><ul><li>多对多关联表 </li></ul><ul><ul><li>戴 3 个表 : category, item, category_item_rel </li></ul></ul><ul><li>... </li></ul>
  16. 16. 表连接查询 <ul><li>交叉连接 , 逗号连接 (cross join) </li></ul><ul><ul><li>select * from a, b where a.id=b.a_id; </li></ul></ul><ul><ul><li>foreach(row in a){ </li></ul></ul><ul><ul><li>foreach(row2 in b){ </li></ul></ul><ul><ul><li> if(a.id == b.a_id){result[] = (row, row2);} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>左连接 </li></ul><ul><ul><li>select * from a left join b on a.id=b.a_id </li></ul></ul><ul><ul><li>foreach(row in a){ </li></ul></ul><ul><ul><li>found = false; </li></ul></ul><ul><ul><li>foreach(row2 in b){ </li></ul></ul><ul><ul><li> if(a.id == b.a_id){ </li></ul></ul><ul><ul><li> found = true; result[] = (row, row2); </li></ul></ul><ul><ul><li> } </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>if(found == false){result[] = (row, NULL);} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  17. 17. 表连接查询应用 <ul><li>category(id, name), item(id, category_id, title) </li></ul><ul><ul><li>在返回结果中包含原表没有的字段 : select item.id, i.name as category_name from item i, category c where i.category_id=c.id; </li></ul></ul>
  18. 18. 经典 SQL 查询语句 <ul><li>分组计数 (group by, having) </li></ul><ul><ul><li>表 log{ip, url, time} </li></ul></ul><ul><ul><li>访问次数最多的 10 个 IP: select ip, count(*) as c from log group by ip order by c desc limit 10 </li></ul></ul><ul><ul><li>访问次数大于 10000 的 IP: select ip, count(*) as c from log group by ip having c>10000, 不能用 where. </li></ul></ul><ul><li>如何实现”不存在”查询 ? – 找出不包含 item 的 category. </li></ul><ul><ul><li>not in: select * from category where id not in(select distinct category_id from item); </li></ul></ul><ul><ul><li>left join is NULL: select c.* from category c left join item i on c.id=i.id where i.id is NULL; </li></ul></ul><ul><ul><li>... </li></ul></ul>
  19. 19. 数据库优化 <ul><li>索引对查询优化 </li></ul><ul><ul><li>MySQL 简单查询的速度非常快 </li></ul></ul><ul><ul><li>使用 explain 命令来分析 SQL 查询语句 </li></ul></ul><ul><ul><li>一般但不绝对 , 给出现在 WHERE 条件中的字段加索引 </li></ul></ul><ul><ul><li>复杂查询拆分为多次简单查询 , 多次简单查询合并为单个复杂查询 </li></ul></ul><ul><ul><li>http://www.ideawu.net/blog/archives/590.html </li></ul></ul><ul><li>分表 </li></ul><ul><ul><li>横向切分 , 如按 id 段切分 </li></ul></ul><ul><ul><li>纵向切分 , 如把所有外键字段放在单独的表中 </li></ul></ul><ul><li>分库 </li></ul><ul><ul><li>无法使用表关联 </li></ul></ul><ul><li>适度冗余 </li></ul>
  20. 20. MySQL 主从复制 <ul><li>解决问题 : 扩展 , 备份 </li></ul><ul><li>复制是异步的 </li></ul><ul><li>只能往 Master 写 </li></ul><ul><li>既可以从 Master 读 , 也可以从 Slave 读 </li></ul><ul><li>dbproxy 可以根据 sql 语句的类型选择主从 </li></ul>
  21. 21. FAQ IT 牛人 http://www.udpwork.com/
  22. 22. FIN Thanks

×