【问题标题】:Column Copy and Update vs. Column Create and Insert列复制和更新与列创建和插入
【发布时间】:2015-05-12 16:47:19
【问题描述】:

我在 PostgreSQL 9.2.10 中有一个包含 3200 万行和 31 列的表。我正在通过添加具有更新值的列来更改表格。

例如,如果初始表是:

id     initial_color
--     -------------
1      blue
2      red
3      yellow

我正在修改表格,结果是:

id     initial_color     modified_color
--     -------------     --------------
1      blue              blue_green
2      red               red_orange
3      yellow            yellow_brown

我的代码可以读取 initial_color 列并更新值。

鉴于我的表有 3200 万行,并且我必须对 31 列中的 5 列应用此过程,那么最有效的方法是什么?我目前的选择是:

  1. 复制列并更新新列中的行
  2. 创建一个空列并插入新值

我可以一次选择一列,也可以同时选择所有五列。列类型为character varyingcharacter

【问题讨论】:

  • 复制列:那会是什么 SQL 指令?
  • @DanielVérité UPDATE SET = ;
  • UPDATE 不会创建新列吗?我们需要“复制列”语句来复制 DDL。使用第二个选项,我们需要明确指定所有字段。您需要更多代码来计算。
  • 我认为创建一个空列,选择初始列,在内存中改变这些值,然后插入将是最有效的。这是实际命中实际数据库的三个命令。您在内存中完成其余的工作,这要快得多。
  • 这可能有助于blog.codacy.com/2015/05/14/…

标签: sql postgresql database-administration postgresql-performance bulkupdate


【解决方案1】:

列类型是字符变化或字符。

不要使用character,这是一种误解。 varchar 可以,但我建议只使用 text 来获取任意字符数据。

鉴于我的表有 3200 万行并且我必须应用它 31 列中的 5 列的过程,最有效的方法是什么?

如果你没有依赖于现有表的对象(视图、外键、函数),最有效的方法是创建一个新表。像这样的东西(细节取决于你的安装细节):

BEGIN;
LOCK TABLE tbl_org IN SHARE MODE;  -- to prevent concurrent writes

CREATE TABLE tbl_new (LIKE tbl_org INCLUDING STORAGE INCLUDING COMMENTS);

ALTER tbl_new ADD COLUMN modified_color text
            , ADD COLUMN modified_something text;
            -- , etc
INSERT INTO tbl_new (<all columns in order here>)
SELECT <all columns in order here>
    ,  myfunction(initial_color) AS modified_color  -- etc
FROM   tbl_org;
-- ORDER  BY tbl_id;  -- optionally order rows while being at it.

-- Add constraints and indexes like in the original table here

DROP tbl_org;
ALTER tbl_new RENAME TO tbl_org;
COMMIT;

如果你有依赖对象,你需要做更多。

要么是,请务必添加all five at once。如果您在单独的查询中更新每一个,则由于 Postgres 的 MVCC 模型,您每次都会编写另一个行版本。

有更多细节、链接和解释的相关案例:

在创建新表时,您还可以以优化的方式对列进行排序:

【讨论】:

  • 这可能是你最好的选择,Postgres 的更新成本很高
【解决方案2】:

也许我误读了这个问题,但据我所知,您有 2 种可能性来创建包含额外列的表格:

  1. CREATE TABLE
    这将创建一个新表,并且可以使用

    完成填充
    • CREATE TABLE .. AS SELECT.. 用于填充创作或
    • 稍后使用单独的INSERT...SELECT... 正如您所说的那样,这两种变体都不是您想要做的,没有列出所有字段的解决方案
      这也需要复制所有数据(加上新字段)。
  2. ALTER TABLE...ADD ...
    这将创建新列。由于我不知道引用现有列值的任何可能性,您将需要一个额外的UPDATE ..SET... 来填写值。

所以,我没有看到任何方式来实现遵循您的选择 1 的过程。

尽管如此,复制(列)数据只是为了在第二步中覆盖它们在任何情况下都是次优的。更改表添加新列正在执行最少的 I/O。由此看来,即使有可能执行您的选择 1,遵循选择 2 也可以保证按因素获得更好的性能。

因此,执行 2 个语句,其中一个 ALTER TABLE 添加所有新列,然后一个 UPDATE 为这些列提供新值将实现您想要的。

【讨论】:

  • 表应该是一样的。所以你是对的:选项 1 不适用。 otion 2 的问题是我需要明确提供数据类型、排序规则等......如果他们在 alter table 中有一个 COPY COLUMN 语句,我不需要这样做。在这种情况下,他们还可以在物理级别优化数据副本,因为操作定义明确。另一种选择是允许 UPDATE .. SET... 如果新列不存在则创建它。
  • 是的,但是如果您事先不知道表结构,那么明确说明所有列属性实际上应该是一个问题,例如。如果您获得了一个表名和信息以沿该表的第 3 列形成一个新列,以及一个要调用以获取结果值的函数。如果您在编程时知道,这可能有点烦人,但不是真正的问题。其余的可能是对 postgres 人员或 SQL 标准化委员会的功能请求。
  • 嗯,我知道在编程时考虑这个很奇怪。鉴于 DDL 语句更多地用于管理工具。但有时是动态改变其数据库结构的软件。这是我的情况,列名是一个参数。反正这个操作需要指定列就像数据冗余一样……即使使用管理工具也容易出现列创建参数错误的错误。
  • 没错,动态引用数据库元数据并不容易。您将需要使用特定数据库提供的内容。使用 pg,您将需要读取 pg_* 表并检索信息详细信息并从该信息中形成 alter 语句。另一方面,修改模式不被视为需要随时应用于任意数据库的标准动态操作。更改架构更应该是计划中的操作,但并不经常发生。
【解决方案3】:

创建新列(修改颜色),所有记录的值为 NULL 或空白,

运行更新语句,假设您的表名为“Table”。

update table
set modified_color = 'blue_green'
where initial_color = 'blue'

如果我是正确的,这也可以这样工作

update table set modified_color = 'blue_green' where initial_color = 'blue';
update table set modified_color = 'red_orange' where initial_color = 'red';
update table set modified_color = 'yellow_brown' where initial_color = 'yellow';

完成此操作后,您可以进行另一次更新(假设您有另一列,我将称之为 modified_color1)

update table set 'modified_color1'= 'modified_color'

【讨论】:

  • 我不确定这是否适用于其他 DBMS。但是 postgresql 说的是: unknown column "modified_color" The new column must be created before.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-30
  • 2015-04-10
  • 1970-01-01
相关资源
最近更新 更多