select * from (select a,b,c ...) 结果列的保证顺序?

select * from (select a,b,c ...) guaranteed order of result columns?

我最近在代码审查中发表评论:

it's better to enumerate the fields explicitly. "select *" doesn't guarantee an order

对于像 select * from (select a,b,c ...) 这样的查询,在这种情况下是这样吗?我无法想象一个数据库引擎会重新排序结果中的列,但我的想象比某些数据库引擎更合乎逻辑。

列始终按照 table 中定义的顺序排列。但是,如果没有包含 order by 子句,则行并不总是以相同的顺序获取。

针对 select * 的建议主要针对直接查询 table 的情况。

在某些数据库中,可以在 table 中途插入一个新列,这样 table t (a, b) 就变成了 table t (a, c, b)。 PostgreSQL(还)不支持这一点,但它仍然可以追加列,并且可以从任何地方删除列,所以如果你添加 c 并删除 b,你仍然可以获得 t (a, c)

这就是为什么在生产查询中使用 * 被认为是不好的做法,尤其是当您的应用程序依赖于序号列位置来读取结果时。但实际上,这仅适用于您未在查询中的其他地方指定字段的情况。

在你的情况下,你在子查询中这样做。所以 * 是绝对安全的,IMO 完全接受 table 这种用法。

这个:

select * from (select a,b,c ... from t)

很好。

这个:

select * from t

select * from (select * from t)

是有问题的,因为它们使应用程序未定义列顺序。即便如此,如果您的应用程序 假定 列顺序而不检查查询元数据,这只是一个问题。

就我个人而言,大多数时候我更喜欢完全限定我的专栏,但确实有时 * 是最易读的选项。

另外,IMO,当客户端应用程序按名称而不是序号读取列时,使用 select * 也很好。如果你的应用程序从不关心 c 是第 2 列还是第 3 列,因为它使用结果元数据来构建行字典(就像 Perl 的 DBI 或 Python 的 psycopg2 可以做的那样)那么没有真正的理由不要只使用 *.

不过,当您只需要一部分列时,SELECT * 可能会产生性能成本。错失了使用仅索引扫描的机会,不必要地获取离线 TOAST 数据,以及因不需要的值而浪费的带宽等等。所以大多数时候它仍然不是一个好主意。