无数次,例如现在,我需要更改表中列的顺序。
例如,当我改进CREATE TABLE
库中的 SQL 代码时,通过在表中的某处添加一列,然后我需要使我的“实时”表反映这些更改。当我添加新列时,它被放置在最后/“右侧”,并且拒绝让我指定它应该去的位置。
虽然这可能对性能影响很小或没有影响,但知道“实时”表和 SQL 代码中定义的表之间的列顺序不同是非常烦人的。
我读过 Stack Exchange 上有关此问题的问题,并多年来多次询问 PG 开发人员。他们莫名其妙地不支持对列重新排序,而是提出可笑的“解决方案”,例如转储整个数据库并将其重新加载,或者创建一个单独的“视图”,或者许多其他奇怪的解决方法,这些解决方法是不切实际的,并且在许多情况下比顺序错误更糟糕的情况。
我不是在问如何做到这一点,因为这显然是不可能的。我只是想知道为什么这是不可能的。我无法想象对列重新排序存在真正的技术挑战,但也许确实存在?从我从 PG 开发者/社区那里得到的态度/氛围来看,这对我来说就像是他们可以轻松修复但出于某些哲学原因而无法修复的事情之一。
真正的原因是什么?对于 PG 来说,简单地交换一些内部数字以使列获得所需的顺序真的那么困难吗?让两个相关的列永远彼此远离看起来真的很难看,这是对我在最初创建表时没有立即考虑后面的列的惩罚。
这有一个非常重要的概念原因,也有为什么没人愿意实施它的原因。
在 SQL 中,表中列的顺序仅在您使用时才重要
SELECT * FROM ...
Run Code Online (Sandbox Code Playgroud)
这是你永远不应该在代码中使用的东西:
如果有人添加或删除列,结果集的列将突然更改,并且您不会收到数据库错误,但客户端应用程序可能会对现在返回的不同数据感到惊讶。
如果连接表,您可能会突然得到一个结果集,其中多个列具有相同的名称。这可能会在客户端造成混乱,并且会使CREATE VIEW
语句彻底失败。
即使它不会导致上述问题之一,您通常也会最终获取并不真正需要的行,这会导致不必要的流量、处理和可能的 deTOAST。
如果您显式指定列表中的列SELECT
,则表中列的顺序无关。
实际上,有两个小点可以使列顺序产生影响:
对齐和填充:
PostgreSQL 中的每种数据类型都有一个对齐方式。bigint
例如,8 个字节的对齐意味着数据只能存储在 8 的倍数的内存地址处。现在,如果在(对齐 2)之后紧接着有一个(对齐 8) smallint
,则最终可能会得到这些列之间浪费了 6 个字节的“填充”空间。
从行中提取数据:
如果要从一行中提取第 100 列,则必须跳过前 99 列。这比访问第一列的成本更高。
但在实践中,像这样的性能和存储空间优化并没有太大的效果。
由于表行按列顺序存储,因此更改列顺序将意味着重写整个表。因此,它不会比导出和导入快得多。
并且已经有一些方法可以解决这个“缺点”:
“步行”:
BEGIN;
CREATE TABLE tab_copy (col1 type1, col2 type2, ...);
INSERT INTO tab_copy SELECT col12, col5, col1, ... FROM tab;
DROP TABLE tab;
ALTER TABLE tab_copy RENAME TO tab;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
这过于简单化了:您还必须处理外键和其他约束。
但本质上您已经可以对列进行重新排序,但它并不像想象的那么简单。
您可以使用视图:
CREATE VIEW newtab AS SELECT col12, col5, col1, ... FROM tab;
Run Code Online (Sandbox Code Playgroud)
SELECT
此类视图可以是、INSERT
UPDATE
和的目标DELETE
。
为了实现这一点,已经做出了认真的努力,但事实证明,乍一看这个问题更加困难,而且由于有解决方法,所以解决这个问题的压力似乎不够高。
归档时间: |
|
查看次数: |
7019 次 |
最近记录: |