知识卡片

SELECT星号的双刃剑

操作参考卡

内容

SELECT *只在”涉及哪些列、以及列的自左向右顺序都无关紧要”的场合是安全的 ——典型场景是EXISTS调用(EXISTS(SELECT * FROM ...)只关心结果表是否非空, 根本不关心具体列内容)。除此之外的场合,SELECT *都是危险的:星号的含义 会随着底层表结构变化而悄悄改变——给一张已有表新增一列,所有依赖SELECT * 的旧代码会在毫无警示的情况下自动”继承”这个新列,可能破坏原本假设列数、 列序固定的下游逻辑。实践建议是时刻警惕并尽量避开这种用法,尤其不要在游标 定义的最外层使用SELECT *(应该一直显式列出所需列名),视图定义同理。 不过这条建议有一个折中方案:如果已经遵循[[SQL列命名与位置依赖关系化使用 SQL的实践规则]]里”始终通过视图存取数据库”的策略,那么只要保证这些视图自身 的定义没有用SELECT *,视图之外的地方使用SELECT *就是安全的(因为视图 已经把列的具体范围固定住了,视图之外的星号顶多是”选取这个已经固定好的 列集合”,不会因底层基表结构变化而漂移)。

参考来源

- 位置:《SQL与关系数据库理论——如何编写健壮的SQL代码》第12章"关于SQL的 其他主题"12.1节"SELECT *"(源文件:OEBPS/text00134.html) - 结论依据:原文明确"SQL SELECT子句对于'SELECT*'的使用在所涉及列不相关 并且列的自左向右排序也不相关的情况下……是可接受的。然而,此种用法在 其他情况下却是危险的,因为'*'的含义在……增加新列的情况下会发生改变…… 尤其是不要在游标定义的最外层使用'SELECT*'……如果……'通过视图运算'的 策略……那么只要不在这些视图的定义中使用'SELECT*'就行,在其他地方 'SELECT*'怎么用都是安全的"。 - 原始内容:此种用法在其他情况下却是危险的,因为"*"的含义在增加新列的 情况下会发生改变……只要不在这些视图的定义中使用"SELECT*"就行,在其他 地方"SELECT*"怎么用都是安全的。