我有一个包含一百万行的数据库,我想获取所有行并对它们进行一些操作,然后将它们插入另一个表(newTable)。
我发现我需要使用服务器端游标,因为我无法将所有数据都提取到内存中。 我还想出了我需要使用两个连接,所以当我提交时,我不会松开我制作的光标。
但现在我的问题是,它不会将所有记录放入newTable中,因为它在日志中显示。 在控制台日志中,我看到它试图将500,000条记录插入数据库
560530 inserting 20551581 and 2176511
但是当我对创建的表进行计数时(虽然它正在进行)它在新表中只显示了大约10,000行。
select count(*) from newTable;
count
-------
10236
当程序结束时,我在新表中只有大约11000条记录,而在记录中它显示它试图插入至少200万行。我的代码怎么了?
def fillMyTable(self):
try:
self.con=psycopg2.connect(database='XXXX',user='XXXX',password='XXXX',host='localhost')
cur=self.con.cursor(name="mycursor")
cur.arraysize=1000
cur.itersize=2000
self.con2=psycopg2.connect(database='XXXX',user='XXXX',password='XXXX',host='localhost')
cur2=self.con2.cursor()
q="SELECT id,oldgroups from oldTable;"
cur.execute(q)
i=0
while True:
batch= cur.fetchmany()
if not batch:
break
for row in batch:
userid=row[0]
groupids=self.doSomethingOnGroups(row[1])
for groupid in groupids:
# insert only if it does NOT exist
i+=1
print (str(i)+" inserting "+str(userid)+" and "+str(groupid))
q2="INSERT INTO newTable (userid, groupid) SELECT %s, %s WHERE NOT EXISTS ( SELECT %s FROM newTable WHERE groupid = %s);"%(userid,groupid,userid,groupid)
cur2.execute(q2)
self.con2.commit()
except psycopg2.DatabaseError, e:
self.writeLog(e)
finally:
cur.close()
self.con2.commit()
self.con.close()
self.con2.close()
更新:我还注意到它使用了很多我的RAM,不是服务器端游标不应该这样做吗?
Cpu(s):15.2%us,6.4%sy,0.0%ni,56.5%id,2.8%wa,0.0%hi,0.2%si, 18.9%st Mem:1695220k总计,1680496k使用,14724k免费,3084k缓冲交换:总共0k,0k使用,0k免费, 1395020k缓存
答案 0 :(得分:1)
如果oldgroups列的格式为1,3,6,7
,则可以使用:
insert into newTable (userid, groupid)
select id, groupid
from (
select
id,
regexp_split_to_table(olgroups, ',') as groupid
from oldTable
) o
where
not exists (
select 1
from newTable
where groupid = o.groupid
)
and groupid < 10000000
但我怀疑你想要检查是否存在groupid和id:
insert into newTable (userid, groupid)
select id, groupid
from (
select
id,
regexp_split_to_table(olgroups, ',') as groupid
from oldTable
) o
where
not exists (
select 1
from newTable
where groupid = o.groupid and id = o.id
)
and groupid < 10000000
regexp_split_to_table
函数将“爆炸”与id列交叉连接的行中的oldgroups
列。