当前位置:首页 > 问答 > 正文

视图在数据库里改数据的那些限制和不方便你得注意点

你得明白,视图看起来像一张表,能查数据,但它本身不存数据,数据实际上躺在底层那些真正的表里,通过视图去改数据,本质上是在改它背后的基表,这个“拐个弯”的操作,就带来了很多条条框框,一不小心就会出错。

视图在数据库里改数据的那些限制和不方便你得注意点

第一大类限制:视图的创建方式本身就埋下了坑。

视图在数据库里改数据的那些限制和不方便你得注意点

不是随便一个视图都能改,如果视图是用很复杂的方式拼凑出来的,那数据库根本没法知道你的修改意图应该对应到基表的哪一行、哪一列。

视图在数据库里改数据的那些限制和不方便你得注意点

  • 来源参考:数据库的“可更新视图”规则。 视图的定义里如果包含了DISTINCT关键字来去重,就不能修改,为什么呢?因为视图显示的结果是去重后的,但底层的表数据可能有多条记录才产生了这个重复值,你通过视图想改其中“一条”记录,数据库懵了:我到底该改底层哪一条对应的记录呢?为了避免这种混乱,数据库直接禁止修改。
  • 来源参考:聚合操作的限制。 如果视图里用了GROUP BY(分组)、SUM()COUNT()这类汇总函数,那这个视图绝对是只读的,这很好理解,视图里显示的是汇总结果,比如一个部门的工资总和,你难道能直接修改这个总和吗?数据库不知道你是想给每个人加薪,还是修改某个人的记录,它无法把对汇总值的修改反向推算出对基表的具体改动,所以干脆不让改。
  • 来源参考:连接查询的歧义。 这是最常见也最头疼的限制,如果视图是由多张表连接(JOIN)组成的,那么通过这个视图修改数据会非常麻烦,很多时候根本不行,特别是当你试图修改一个涉及多张表字段的视图时,数据库很难判断你的修改是针对哪张表的,即使只修改其中一张表的字段,如果连接条件复杂,数据库也可能因为无法唯一确定要更新的基表行而拒绝操作,你有一个视图,连接了用户表和订单表,你想通过视图修改用户的电话号码,这个操作理论上可以只影响用户表,但如果两表之间存在一对多关系(一个用户有多个订单),数据库在更新用户表时通常没问题,但如果你想插入一条新数据,问题就大了:这条新记录既包含用户信息又包含订单信息,你到底是只想插入一个新用户,还是想为一个已存在的用户插入一个新订单?数据库无法自动做出判断。

第二大类限制:哪怕视图理论上可更新,具体操作也处处是雷。

  • 插入(INSERT)数据最难成功。 即使你的视图只基于一张表,但如果视图没有包含基表里所有“不能为空(NOT NULL)”且没有默认值的字段,那么通过视图插入数据就会失败,因为插入操作必须为所有必需的字段提供值,而视图没包含这些字段,你又没法通过视图给它们赋值,数据库无法完成完整的插入,如果视图包含了表达式或计算字段,你也无法向这些“虚拟”的字段插入值,因为它们不是真实存在的存储列。
  • 修改(UPDATE)可能被“静默”忽略。 这是非常危险的一点,假设你有一个视图,只显示了员工表中工资大于5000的记录,你通过这个视图,想把某个员工的工资从6000改成4000,这个操作在某些数据库系统中可能会成功执行,但结果会让人大跌眼镜:这条记录从视图中消失了!因为更新后,该员工的工资变成了4000,不再满足视图的筛选条件(>5000),你通过视图再也查不到这条记录,会让你误以为修改失败或数据丢失了,其实数据还在基表里,只是不符合视图的“过滤条件”了,这种“静默”的成功,比直接的错误更可怕。
  • 删除(DELETE)操作的条件苛刻。 删除操作相对直接,但它也严重依赖于视图的定义,如果视图是基于多表连接定义的,那么通过视图删除数据通常是不被允许的,因为数据库无法确定你到底想删除哪张表里的数据(是删除主表记录,还是关联表记录?删除主表记录可能会因为外键约束而失败),即使视图基于单表,如果视图包含了GROUP BYDISTINCT等操作,删除也同样被禁止。

第三大类不方便:权限和性能的隐形问题。

  • 来源参考:权限的分离。 你对视图有增删改的权限,不代表你对它底层的基表有相应的权限,数据库管理员(DBA)可能会给你开视图的更新权限,但出于安全考虑,没有给你基表的权限,这时候你操作视图更新,会报权限错误,排查起来比较麻烦。
  • 性能可能更差。 通过视图更新数据,数据库需要先解析视图定义,再转换成对基表的操作,这个转换过程需要额外的计算开销,对于简单的视图,这点开销可以忽略不计,但如果视图定义非常复杂(嵌套了多层视图或复杂的查询逻辑),那么更新操作的性能可能会比直接操作基表差很多。

总结一下核心的不方便点:

最大的问题就是不确定性复杂性,视图像一个带有特定滤镜和规则的观察窗口,你通过这个窗口去改动屋里的东西(基表),规则非常死板,数据库为了保证数据的一致性和可追溯性,设置了很多“保护罩”,你必须非常清楚你创建的视图到底是什么结构(基于单表还是多表?有没有用聚合函数?有没有去重?),才能预测更新操作是否可行、会产生什么后果,否则,很容易遇到“命令执行失败”或者更糟的“执行成功了但结果诡异”的情况,在实际工作中,对于更新操作,尤其是插入和删除,开发人员往往会更倾向于直接操作那些结构清晰、确定的基表,而不是通过视图这个“中间商”,以避免不必要的麻烦和潜在风险,视图的优势在于简化查询和权限控制,而非数据修改。