在postgres中复制表(包括索引)


85

我有一张postgres桌子。我需要从中删除一些数据。我打算创建一个临时表,将数据复制到其中,重新创建索引并删除所需的行。我无法从原始表中删除数据,因为该原始表是数据源。在一种情况下,我需要得到一些取决于删除X的结果,在另一种情况下,我需要删除Y。因此,我需要所有原始数据始终存在并可用。

但是,重新创建表并再次将其复制并重新创建索引似乎有点愚蠢。无论如何,postgres都会告诉它“我想要该表的完整单独副本,包括结构,数据和索引”吗?

不幸的是PostgreSQL没有“ CREATE TABLE..LIKE X INCLUDING INDEXES”

Answers:


108

新的PostgreSQL(根据docs 8.3开始)可以使用“ INCLUDING INDEXES”:

# select version();
                                             version
-------------------------------------------------------------------------------------------------
 PostgreSQL 8.3.7 on x86_64-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
(1 row)

如您所见,我正在8.3上进行测试。

现在,让我们创建表:

# create table x1 (id serial primary key, x text unique);
NOTICE:  CREATE TABLE will create implicit sequence "x1_id_seq" for serial column "x1.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x1_pkey" for table "x1"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x1_x_key" for table "x1"
CREATE TABLE

并查看其外观:

# \d x1
                         Table "public.x1"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x1_pkey" PRIMARY KEY, btree (id)
    "x1_x_key" UNIQUE, btree (x)

现在我们可以复制结构:

# create table x2 ( like x1 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x2_pkey" for table "x2"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x2_x_key" for table "x2"
CREATE TABLE

并检查结构:

# \d x2
                         Table "public.x2"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x2_pkey" PRIMARY KEY, btree (id)
    "x2_x_key" UNIQUE, btree (x)

如果您使用的是PostgreSQL 8.3之前的版本,则可以简单地将pg_dump与选项“ -t”一起使用来指定1个表,在转储中更改表名,然后再次加载它:

=> pg_dump -t x2 | sed 's/x2/x3/g' | psql
SET
SET
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE

现在的表是:

# \d x3
                         Table "public.x3"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x3_pkey" PRIMARY KEY, btree (id)
    "x3_x_key" UNIQUE, btree (x)

14
这样,主键序列(x1_id_seq)将在两个表之间共享!
Jauzsika 2011年

2
使用pg9.X的操作,在使用“包含约束”(而非“包含索引”)时将共享主键序列。
彼得·克劳斯

44
[CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name
    [ (column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
    [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
    [ TABLESPACE tablespace ]
    AS query][1]  

这是一个例子

CREATE TABLE films_recent AS
  SELECT * FROM films WHERE date_prod >= '2002-01-01';

从第一种方法创建新表的另一种方法是使用

    CREATE TABLE films_recent (LIKE films INCLUDING INDEXES);  

    INSERT INTO films_recent
         SELECT *
           FROM books
          WHERE date_prod >= '2002-01-01';  

请注意,如果使用第二种方法,则Postgresql会发布补丁来修复表空间问题


postgres中没有“ INCLUDING INDEXES”。
罗里

2
您正在使用什么版本?阅读最新的文档,它在那里
WolfmanDragon

6
对于pg9.X,当使用“ INCLUDING CONSTRAINTS”(不是“ INCLUING INDEXES”)时,主键序列将在两个表之间共享(!)。
彼得·克劳斯

看起来可能需要CREATE TABLE my_table (LIKE...)代替它CREATE TABLE my_table LIKE...才能工作。编辑答案。
杰森·斯威特

@PeterKrauss您知道共享主键序列是什么吗?我正在尝试将一堆数据复制到一个新表中。我不能删除旧表并重命名新表,因为新表中的pk指向旧表。
yellottyellott

4

我有一张postgres桌子。我需要从中删除一些数据。

我认为...

delete from yourtable
where <condition(s)>

...由于某种原因无法正常工作。(是否愿意分享这个理由?)

我打算创建一个临时表,将数据复制到其中,重新创建索引并删除所需的行。

查看pg_dump和pg_restore。使用带有一些聪明选项的pg_dump,也许在pg_restoring之前编辑输出可能会成功。


由于您正在对数据进行“假设”类型分析,因此我想知道使用视图是否会更好。

您可以根据要排除的内容的否定为每个要测试的方案定义一个视图。即,根据您要包含的内容定义视图。例如,如果要在“删除” X = Y的行的数据上创建“窗口”,则可以将视图创建为其中(X!= Y)的行。

视图作为定义查询存储在数据库中(系统目录中)。每次查询视图时,数据库服务器都会查询定义该视图的基础查询并执行该查询(与您使用的任何其他条件进行“与”操作)。这种方法有几个好处:

  1. 您绝不会复制数据的任何部分。
  2. 当您查询每个视图/场景时,将使用已经用于基表(您的原始“真实”表)的索引(查询优化器认为合适)。无需重新定义或复制它们。
  3. 由于视图是基表中“真实”数据的“窗口”(而不是快照),因此您可以在基表中添加/更新/删除,并且只需重新查询视图方案即可,而无需重新创建任何内容。数据随时间变化。

当然,需要权衡取舍。由于视图是虚拟表,而不是“真实”(基本)表,因此,每次访问它时,您实际上是在执行一个(也许很复杂的)查询。这可能会使速度变慢。但事实并非如此。它取决于许多问题(数据的大小和性质,系统目录中统计信息的质量,硬件的速度,使用负载等)。除非您尝试一下,否则您不会知道。如果(且仅)当您实际上发现性能降低到令人无法接受的程度,那么您可能会考虑其他选择。(材料化的视图,表的副本,等等。。。


我已经更新了问题,以解释为什么我不能只从原始表中删除
Rory,

4

网上有很多答案,可以在这里找到其中之一。

我最终做了这样的事情:

create table NEW ( like ORIGINAL including all);
insert into NEW select * from ORIGINAL

这将复制模式和数据,包括索引,但不包括触发器和约束。请注意,索引与原始表共享,因此当向其中一个表添加新行时,计数器将增加。


1

使用选择创建一个新表以获取所需的数据。然后将旧表换成新表。

create table mynewone as select * from myoldone where ...
mess (re-create) with indexes after the table swap.

0

一种简单的方法是包含所有内容:

CREATE TABLE new_table (LIKE original_table INCLUDING ALL);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.