知识卡片

属性名依赖问题与程序内外部数据独立定义的正确方案

普通读书笔记卡

内容

关系代数运算符高度依赖恰当的属性命名(如自然连接靠同名属性建立对应),这带来 一个看似脆弱的疑虑:如果给某个关系变量新增一个属性、恰好和另一个关系变量已有 的属性同名,会不会破坏原有查询?书中先澄清:这不是设计漏洞——同名属性被要求 必须同类型(形式上说就是”同一个属性”),不同类型的属性必须用不同名字,这条 约束本身不构成实质限制,因为[[类型推理规则与RENAME运算符的必要性]]中的RENAME 运算符总能在需要时化解命名冲突。真正的问题根源在别处:当今大多数SQL系统里, 应用程序访问数据库靠调用级接口或嵌入式SQL,这意味着数据库定义实际上并不是 程序类型结构的一部分——一句常被引用的话是”如果数据库定义真的是程序类型结构 的一部分,那么大部分数据库应用程序的编程错误都会显式为类型错误”,但现实中 它们不是,这个缺陷可以追溯到上世纪60年代对”数据独立性”的一个部分性误解: 当时认为要实现数据独立性,只需要把数据库定义和程序分离即可;但真正需要的其实 是两份独立的定义——一份存在于程序内部(代表开发者对数据库的认知,同时支持 编译期查询检查),一份存在于程序外部(代表”如现实一般”的真实数据库结构), 后期如果外部定义需要变更,只要调整两者之间的映射关系,就能在完全不改动程序 代码的前提下维持逻辑独立性(书中用假设的”公共表”CREATE PUBLIC TABLE语法 和显式映射定义演示了这套机制该怎样工作,如果SP表后来新增SNAME列,只需要 调整映射本身,应用程序完全不用变化)。可惜当今SQL产品并未真正实现这套双层 定义机制,S NATURAL JOIN SPSELECT * FROM S这类表达式因此确实会遇到 “脆弱”问题;退而求其次的实用对策仍然是[[SQL列命名与位置依赖关系化使用SQL的 实践规则]]里已给出的策略:为每张基表定义遵循统一命名规则的视图,程序只对 视图而不对底层基表编写查询,基表结构变化时只需调整视图定义。

参考来源

- 位置:《SQL与关系数据库理论——如何编写健壮的SQL代码》第6章"SQL和关系代数 I:原始运算符"6.12节"属性名依赖"(源文件:OEBPS/text00071.html) - 结论依据:原文明确"如果数据库定义真的是程序类型结构的一部分,那么大部分 数据库应用程序的编程错误都会显式为类型错误……真正需要的是两个分离的定义: 一个在程序内部……另外一个在程序外部……如果后期有必要将数据库定义更改得 '如现实一般',那么数据的逻辑独立性可以通过改变两个定义之间映射关系得以 维持……可惜,当今的SQL产品并没有这么做"。 - 原始内容:如果数据库定义真的是程序类型结构的一部分,那么大部分数据库应用 程序的编程错误都会显式为类型错误……真正需要的是两个分离的定义……可惜, 当今的SQL产品并没有这么做。