【发布时间】:2010-09-29 17:08:58
【问题描述】:
我有一个生产数据库,比如一千万行。我想从过去一个小时的生产中提取大约 10,000 行并将它们复制到我的本地盒子。我该怎么做?
假设查询是:
SELECT * FROM mytable WHERE date > '2009-01-05 12:00:00';
如何获取输出,将其导出到某种转储文件,然后将该转储文件导入到我的本地数据库开发副本中 - 尽可能快速和轻松?
【问题讨论】:
标签: sql postgresql
我有一个生产数据库,比如一千万行。我想从过去一个小时的生产中提取大约 10,000 行并将它们复制到我的本地盒子。我该怎么做?
假设查询是:
SELECT * FROM mytable WHERE date > '2009-01-05 12:00:00';
如何获取输出,将其导出到某种转储文件,然后将该转储文件导入到我的本地数据库开发副本中 - 尽可能快速和轻松?
【问题讨论】:
标签: sql postgresql
在psql 中,您只需将copy 与您提供给我们的查询一起使用,将其导出为CSV(或任何格式),使用\c 切换数据库并导入它。
在psql 中查看\h copy。
【讨论】:
使用您添加的约束(不是超级用户),我找不到纯 SQL 解决方案。但是用你最喜欢的语言做这件事很简单。您打开一个到“旧”数据库的连接,另一个连接到新数据库,您在一个中选择并在另一个中插入。这是一个在 Python 中经过测试和工作的解决方案。
#!/usr/bin/python
"""
Copy a *part* of a database to another one. See
<http://stackoverflow.com/questions/414849/whats-the-best-way-to-copy-a-subset-of-a-tables-rows-from-one-database-to-anoth>
With PostgreSQL, the only pure-SQL solution is to use COPY, which is
not available to the ordinary user.
Stephane Bortzmeyer <bortzmeyer@nic.fr>
"""
table_name = "Tests"
# List here the columns you want to copy. Yes, "*" would be simpler
# but also more brittle.
names = ["id", "uuid", "date", "domain", "broken", "spf"]
constraint = "date > '2009-01-01'"
import psycopg2
old_db = psycopg2.connect("dbname=dnswitness-spf")
new_db = psycopg2.connect("dbname=essais")
old_cursor = old_db.cursor()
old_cursor.execute("""SET TRANSACTION READ ONLY""") # Security
new_cursor = new_db.cursor()
old_cursor.execute("""SELECT %s FROM %s WHERE %s """ % \
(",".join(names), table_name, constraint))
print "%i rows retrieved" % old_cursor.rowcount
new_cursor.execute("""BEGIN""")
placeholders = []
namesandvalues = {}
for name in names:
placeholders.append("%%(%s)s" % name)
for row in old_cursor.fetchall():
i = 0
for name in names:
namesandvalues[name] = row[i]
i = i + 1
command = "INSERT INTO %s (%s) VALUES (%s)" % \
(table_name, ",".join(names), ",".join(placeholders))
new_cursor.execute(command, namesandvalues)
new_cursor.execute("""COMMIT""")
old_cursor.close()
new_cursor.close()
old_db.close()
new_db.close()
【讨论】:
源服务器:
BEGIN;
CREATE TEMP TABLE mmm_your_table_here AS
SELECT * FROM your_table_here WHERE your_condition_here;
COPY mmm_your_table_here TO 'u:\\source.copy';
ROLLBACK;
您的本地盒子:
-- your_destination_table_here must be created first on your box
COPY your_destination_table_here FROM 'u:\\source.copy';
【讨论】:
来源:
psql -c "COPY (SELECT * FROM mytable WHERE ...) TO STDOUT" > mytable.copy
目的地:
psql -c "COPY mytable FROM STDIN" < mytable.copy
这假定 mytable 在源和目标中具有相同的架构和列顺序。如果不是这种情况,您可以尝试STDOUT CSV HEADER 和STDIN CSV HEADER 而不是STDOUT 和STDIN,但我没有尝试过。
如果您在 mytable 上有任何自定义触发器,您可能需要在导入时禁用它们:
psql -c "ALTER TABLE mytable DISABLE TRIGGER USER; \
COPY mytable FROM STDIN; \
ALTER TABLE mytable ENABLE TRIGGER USER" < mytable.copy
【讨论】: