我编写了一个Python脚本,它采用1.5 G XML文件,解析数据并使用copy_from将其提供给数据库。它每1000个解析的节点调用以下函数。总共有大约170k个节点,更新大约300k行或更多。它开始时非常快,然后随着时间的推移逐渐变慢。关于为什么会发生这种情况的任何想法以及我可以做些什么来解决它?
这是我将数据提供给db的功能。
def db_update(val_str, tbl, cols):
conn = psycopg2.connect("dbname=<mydb> user=postgres password=<mypw>")
cur = conn.cursor()
output = cStringIO.StringIO()
output.write(val_str)
output.seek(0)
cur.copy_from(output, tbl, sep='\t', columns=(cols))
conn.commit()
我没有包含xml解析,因为我不认为这是一个问题。如果没有db,解析器将在2分钟内执行。
答案 0 :(得分:1)
随着表的增长,有几件事可能会减慢插入速度:
禁用任何非关键触发器,或者如果不可能,则重新设计它们以在恒定时间运行。
删除索引,然后在加载数据后创建它们。如果您需要实际INSERT
或UPDATE
的任何索引,您需要让他们承担费用。
如果你正在做很多UPDATE
次,请定期考虑VACUUM
表,或者设置autovacuum以非常积极地运行。这将有助于Pg重用空间而不是从文件系统中更昂贵地分配新空间,并有助于避免表格膨胀。
您还可以通过不为每个工作块重新连接来节省时间。保持联系。
答案 1 :(得分:0)
根据个人经验,copy_from在您提交任何内容后不会更新任何索引,因此您必须在以后执行此操作。我会将你的conn = psycopg2.connect("dbname=<mydb> user=postgres password=<mypw>"); cur = conn.cursor()
移到函数之外并在你完成插入所有内容时执行commit()(我建议每行提交~100k行,否则它会开始变慢)。
此外,它可能看起来很愚蠢,但它发生在我身上很多次:确保在调用db_update后重置val_str。对我来说,当copy_from / inserts开始变慢时,因为我插入相同的行加上更多行。
答案 2 :(得分:0)
我使用以下内容,据我所知,我的表现并没有受到任何影响:
import psycopg2
import psycopg2.extras
local_conn_string = """
host='localhost'
port='5432'
dbname='backupdata'
user='postgres'
password='123'"""
local_conn = psycopg2.connect(local_conn_string)
local_cursor = local_conn.cursor(
'cursor_unique_name',
cursor_factory=psycopg2.extras.DictCursor)
我在代码中输出了以下输出来测试运行时(我解析了很多行。超过30.000.000)。
Parsed 2600000 rows in 00:25:21
Parsed 2700000 rows in 00:26:19
Parsed 2800000 rows in 00:27:16
Parsed 2900000 rows in 00:28:15
Parsed 3000000 rows in 00:29:13
Parsed 3100000 rows in 00:30:11
我必须提到我不要复制&#34;任何东西。但是我正在将我的行从远程PostGreSQL移动到本地,并且在此过程中创建了一些表来比我的数据更好地索引我的数据,因为30.000.000+对于常规查询来说有点太多了。
我认为这与我cursor
的创建方式有关。
我使用以下命令运行我的查询:
local_cursor.execute("""SELECT * FROM data;""")
row_count = 0
for row in local_cursor:
if(row_count % 100000 == 0 and row_count != 0):
print("Parsed %s rows in %s" % (row_count,
my_timer.get_time_hhmmss()
))
parse_row(row)
row_count += 1
print("Finished running script!")
print("Parsed %s rows" % row_count)
my_timer
是我制作的计时器类,parse_row(row)
函数格式化我的数据,将其传输到我的本地数据库,并在数据验证后最终从远程数据库中删除已移至我当地的数据库。
即使解析了大约4.000.000个查询,解析我的数据库中每隔100.000行大约需要1分钟:
Parsed 3800000 rows in 00:36:56
Parsed 3900000 rows in 00:37:54
Parsed 4000000 rows in 00:38:52
Parsed 4100000 rows in 00:39:50