注:本文使用mysql5.5版本为例。
 
做过数据库开发的同学,对视图(VIEW)应该不会陌生。
 
我接触视图最多的应用场景有两个:
1)出于权限问题,为了限制访问者看到过多的表字段(或内容),就建立一个视图供TA使用。
2)也可以为了查询方便,将多张表合并到一个视图里使用。
 
比如,我最近遇到一个这样的需求:
 
有四种用户类型的表,有部分相同的信息,当然也会有很多不相同的字段:
T_USER_PERSON(ID, PERSON_NAME, CREATE_TIME, …)
T_USER_TEAM(ID, TEAM_NAME, CREATE_TIME, …)
T_USER_COMPANY(ID, COMPANY_NAME, CREATE_TIME, ...)
T_USER_ORGANIZATION(ID, ORGANIZATION_NAME, CREATE_TIME, ...)
 
还有一张业务表,汇集了这四种用户分别创建的业务数据:
T_BUSSINESS(ID, USER_ID, USER_TYPE, CONTENT, ...)
USER_TYPE 是枚举类型:PERSON, TEAM, COMPANY, ORGANIZATION
由USER_ID和USER_TYPE来关联哪类的哪个用户,创建了这条业务数据。
 
关系图大概是这样的:
 

 
我第一个就想到了使用视图➡建立一个视图统一管理所有用户,再跟业务表关联查询,业务逻辑多么清晰!
于是,我建立这张视图,如下:
CREATE OR REPLACE VIEW VIEW_ALL_TYPE_USER as
select id id, PERSON_NAME user_name, 'PERSON' user_type, create_time create_time from T_USER_PERSON
UNION ALL
select id as id, COMPANY_NAME as user_name, 'COMPANY' as user_type, create_time create_time from T_USER_COMPANY
UNION ALL
select id as id, ORGANIZATION_NAME as user_name, 'ORGANIZATION' as user_type, create_time create_time from T_USER_ORGANIZATION
UNION ALL
select id as id, TEAM_NAME as user_name, 'TEAM' as user_type, create_time create_time from T_USER_TEAM;
 
改变之后的关系图大概是这样的:

 
联合查询的sql语句如下:
select b.id, b.user_id, v.user_name, b.content
from T_BUSSINESS b
left join VIEW_ALL_TYPE_USER v ON b.user_id=v.user_id and b.user_type=v.user_type
order by b.id desc
 
看起来很简洁,但是运行起来就慢得要死。其实数据量并不大,用户总共大概有12万,业务数据大概1400条。可是,经过视图和表的关联查询,速度是不可以忍受的,我想,这是多重笛卡尔积的结果吧。
 
除了联合查询效率低的问题,视图还不能建立索引,没办法有效提高查询效率。
 
经过再三权衡,我决定放弃视图,宁可使用稍微复杂一些的case-then语句来实现。效果还是可以的。
select b.id,
b.user_id,
b.user_type,
case b.user_type
when 'PERSON' then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id)
when 'ENTERPRISE' then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id)
when 'CHARITY' then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id)
when 'TEAM' then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id)
end as user_name,
b.content
from T_BUSSINESS b
order by b.id desc
 
但是,这样的话,存在一个问题:
如果用别名作为查询条件,会出现错误:Unknown column 'user_name' in 'where clause'
 
1)把别名的查询条件放在table后面:
这种办法对我不起作用,不知道是否是版本的问题……
 
2)用一个select包起来:
注意:每个table,包括最终()起来的虚表都要起个别名
 
3)在查询条件里使用完整的case-then:
在本文中的sql语句应该是:
select b.id,
b.user_id,
b.user_type,
case b.user_type
when 'PERSON' then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id)
when 'ENTERPRISE' then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id)
when 'CHARITY' then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id)
when 'TEAM' then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id)
end as user_name,
b.content
from T_BUSSINESS b
where
case b.user_type
when 'PERSON' then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id)
when 'ENTERPRISE' then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id)
when 'CHARITY' then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id)
when 'TEAM' then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id)
end like '测试%'
order by b.id desc
 
-------------------
 
但是,好景不长,又遇到了问题……
 
新的需求来了,在外面又多了一层查询:
有多种相似的业务,想要放在一起进行排序展示。(这回我学“聪明”了,不考虑视图了)这样,就需要嵌套两层case-then语句……,先不考虑效率问题,这样冗长的SQL的可读性和维护性也太差了吧?
 
又经过再三权衡,我还是决定在业务表里增加一个user_name字段,虽然这是个冗余字段,但会使逻辑更简单,更易于维护。至于user_name数据一致性的问题,解决方法有很多:触发器/异步通知/同步更新等等,都可以实现。毕竟user_name并不是经常修改的。
最终的业务表是这样的(当然,其他的业务表也都增加了USER_NAME字段):
T_BUSSINESS(ID, USER_ID, USER_TYPE, USER_NAME, CONTENT, ...)
 
最后看起来大概是这个样子的:

 
至少,以我目前有限的认识,这样做是最佳方案,希望有更好方法的同学不吝赐教。
 
 
 
 

【原】对MYSQL下视图的一些总结的更多相关文章

  1. MySql下视图的创建

     (1).第一类:create view v as select * from table; (2).第二类:create view v as select id,name,age from ta ...

  2. MySQL之视图、触发器、事务、存储、函数、流程控制

    一.视图 视图就是一个虚拟表,我们把复杂的sql语句后看到的虚拟表封装起来,给他取个名字,当我们下次使用的时候,就不用再去写复杂的sql语句,直接调用封装后的视图名字,就可以得到我们想要的表,然后就可 ...

  3. MySQL之视图、触发器、事务、存储过程、函数 流程控制

    MySQL之视图.触发器.事务.存储过程.函数 阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上全部 ...

  4. 数据库MySQL之 视图、触发器、存储过程、函数、事务、数据库锁、数据库备份、事件

    数据库MySQL之 视图.触发器.存储过程.函数.事务.数据库锁.数据库备份.事件 浏览目录 视图 触发器 存储过程 函数 事务 数据库锁 数据库备份 事件 一.视图 1.视图概念 视图是一个虚拟表, ...

  5. MySQL 的视图、触发器、事务、存储过程、函数

    MySQL 的视图.触发器.事务.存储过程.函数   阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句 ...

  6. day 40 MySQL之视图、触发器、事务、存储过程、函数

    MySQL之视图.触发器.事务.存储过程.函数   阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 MySQL这个软件想将数据处理的所有事情,能够在mysql这个层面上 ...

  7. mysql第五篇 : MySQL 之 视图、触发器、存储过程、函数、事物与数据库锁

    第五篇 : MySQL 之 视图.触发器.存储过程.函数.事物与数据库锁 一.视图 视图是一个虚拟表(非真实存在的),其本质是‘根据SQL语句获取动态的数据集,并为其命名‘ ,用户使用时只需使用“名称 ...

  8. mysql下的SELECT INTO语句

    在mysql下使用SELECT INTO语句会产生ERROR 1327 (42000): Undeclared variable:new_tablename 此时要使用: CREATE TABLE C ...

  9. 第五章 MySQL事务,视图,索引,备份和恢复

    第五章 MySQL事务,视图,索引,备份和恢复 一.事务 1.什么是事务 事务是一种机制,一个操作序列,它包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求.要么都执行 ...

随机推荐

  1. HDU 1214 圆桌会议 圆环逆序

    http://acm.hdu.edu.cn/showproblem.php?pid=1214 题目大意: 一群人围着桌子座,如果在一分钟内一对相邻的人交换位置,问多少分钟后才能得到与原始状态相反的座位 ...

  2. 【习题 3-1 UVA - 1585】Score

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 模拟水题 [错的次数] 在这里输入错的次数 [反思] 在这里输入反思 [代码] #include <bits/stdc++.h ...

  3. Apache与weblogic整合实战(独家研究)

    用apache来处理外界的请求,再把请求转发给wls,这样就行突破wls express版本号的5用户限制 详细配置例如以下 copy ${WLS_Server}/server/lib下的mod_wl ...

  4. 移动开发之css3实现背景几种渐变效果

    移动端背景渐变,非常的年轻,符合90后年轻一代的审美,css3的这个渐变目前主要是应用在手机前端领域. 产品设计中使用渐变色的好处:1:观众不至于眼睛过于疲劳(如果是浅色背景,3个小时下来极容易造成观 ...

  5. [AngularJS Ng-redux] Integrate ngRedux

    Up to this point, we have created an effective, yet rudimentary, implementation of Redux by manually ...

  6. Qt 使用qDebug() 打印Qlist 容器数据(将QDebug()定义成某个类的友元函数)

    当QList<T>容器中的数据用qDebug() 打印时 ,假如 T 是内置类型(int  float ...)与 打印一个字符串使用完全一样,假如T 是一个CustomerClass 那 ...

  7. CSS负边距margin的应用

    原文 简书原文:https://www.jianshu.com/p/75a178e65207 相关文章 CSS负margin的影响:https://www.cnblogs.com/shcrk/p/93 ...

  8. oracle 之 COMMENT 分类: H2_ORACLE 2014-04-24 15:30 386人阅读 评论(0) 收藏

    http://blog.csdn.net/liguihan88/article/details/3002403 无疑注释现在都被大家接受和认可,在大家编程用的IDE中都提供或有第三方插件来支持提取注释 ...

  9. 【35.43%】【hdu 4347】The Closest M Points

    Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others) Total Submissio ...

  10. html5 Canvas和SVG的区别是什么(总结)

    html5 Canvas和SVG的区别是什么(总结) 一.总结 一句话总结:都是2D做图,svg是矢量图,canvas是位图.Canvas 是逐像素进行渲染的,适合游戏. 1.svg的全称是什么? S ...