使用SQL完全复制postgres表

时间:2011-07-06 19:41:11

标签: sql postgresql data-migration

免责声明:此问题类似于堆栈溢出问题here,但这些问题都不适合我的问题,我稍后会解释。

我正在尝试在postgres中复制一个大表(大约40M行,100多列),其中很多列都被索引。目前我使用这个SQL:

CREATE TABLE <tablename>_copy (LIKE <tablename> INCLUDING ALL);
INSERT INTO <tablename>_copy SELECT * FROM <tablename>;

此方法有两个问题:

  1. 它在数据摄取之前添加了索引,因此它比创建没有索引的表所需的时间长,然后在复制所有数据后进行索引。
  2. 这不会正确复制`SERIAL'样式列。它不是在新表上设置新的“计数器”,而是将新表中列的默认值设置为过去表的计数器,这意味着它不会随着行的添加而增加。
  3. 表格大小使索引成为实时问题。它还使得转储到文件然后重新摄取是不可行的。我也没有命令行的优势。我需要在SQL中执行此操作。

    我想要做的是直接用奇迹命令制作精确副本,或者如果不可能的话,复制具有所有约束但没有索引的表,并确保它们是精神上的约束' '(又称SERIAL列的新计数器)。然后使用SELECT *复制所有数据,然后复制所有索引。

    来源

    1. Stack Overflow question about database copying:这不是我要求的原因有三个原因

      • 它使用命令行选项pg_dump -t x2 | sed 's/x2/x3/g' | psql,在此设置中,我无权访问命令行
      • 它创建索引前数据摄取,这很慢
      • 它不会正确更新序列列作为default nextval('x1_id_seq'::regclass)
      • 的证据
    2. Method to reset the sequence value for a postgres table:这很棒,但不幸的是它是非常手动的。

7 个答案:

答案 0 :(得分:53)

答案 1 :(得分:45)

PostgreSQL中的create table as功能现在可能是OP正在寻找的答案。

https://www.postgresql.org/docs/9.5/static/sql-createtableas.html

create table my_table_copy as
  select * from my_table

这将创建一个与数据相同的表。

添加with no data将复制没有数据的架构。

create table my_table_copy as
  select * from my_table
with no data

这将创建包含所有数据的表,但没有索引和触发器等。

create table my_table_copy (like my_table including all)

类似语法的create table将包括所有触发器,索引,约束等。但不包括数据。

答案 2 :(得分:14)

最接近的“奇迹命令”就像是

pg_dump -t tablename | sed -r 's/\btablename\b/tablename_copy/' | psql -f -

特别是,这需要在加载表数据后创建索引。

但这不会重置序列;你必须自己编写脚本。

答案 3 :(得分:4)

要完全复制一个表,包括表结构和数据,请使用以下语句:

CREATE TABLE new_table AS 
TABLE existing_table;

要复制不包含数据的表结构,可将WITH NO DATA子句添加到CREATE TABLE语句中,如下所示:

CREATE TABLE new_table AS 
TABLE existing_table 
WITH NO DATA;

要从现有表中复制包含部分数据的表,请使用以下语句:

CREATE TABLE new_table AS 
SELECT
*
FROM
    existing_table
WHERE
    condition;

答案 4 :(得分:2)

警告:

使用pg_dump和任何类型的正则表达式替换源表名称的所有答案都非常危险。如果您的数据包含您要替换的子字符串,该怎么办?您最终会更改数据!

我建议采用双程解决方案:

  1. 使用某些特定于数据的regexp消除转储中的数据行
  2. 对剩余行执行搜索和替换
  3. 这是一个用Ruby编写的例子:

    ruby -pe 'gsub(/(members?)/, "\\1_copy_20130320") unless $_ =~ /^\d+\t.*(?:t|f)$/' < members-production-20130320.sql > copy_members_table-20130320.sql
    

    在上面我试图将“members”表复制到“members_copy_20130320”中。我的数据特定正则表达式是/ ^ \ d + \ t。*(?:t | f)$ /

    以上类型的解决方案适合我。告诫者......

    修改

    好的,这是针对正则表达式反义词的伪shell语法的另一种方式:

    1. pg_dump -s -t mytable mydb&gt; mytable_schema.sql
    2. mytable_schema.sql中的搜索和替换表名&gt; mytable_copy_schema.sql
    3. psql -f mytable_copy_schema.sql mydb

    4. pg_dump -a -t mytable mydb&gt; mytable_data.sql

    5. 在数据部分之前的少数SQL语句中替换“mytable”
    6. psql -f mytable_data.sql mydb

答案 5 :(得分:0)

显然你想“重建”一张桌子。如果您只想重建一个表而不是复制它,那么您应该使用CLUSTER。

SELECT count(*) FROM table; -- make a seq scan to make sure the table is at least
                            -- decently cached
CLUSTER someindex ON table;

您可以选择索引,尝试选择适合您查询的索引。如果没有其他索引适合,您始终可以使用主键。

如果你的表太大而无法缓存,那么CLUSTER可能会很慢。

答案 6 :(得分:-1)

create table newTableName(就像包含索引的oldTableName); 插入newTableName select * from oldTableName

这对我有用9.3