0

我有一个有一百万行的数据库,我想获取所有行并对它们进行一些操作,然后将它们插入另一个表(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()

更新:我还注意到它使用了我的大量内存,服务器端光标不应该这样做吗?

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 内存: 1695220k 总计, 1680496k 已使用, 14724k 空闲, 3084k 缓冲区交换:总共 0k,使用 0k,免费 0k,缓存 1395020k

4

1 回答 1

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函数将“分解”行中的oldgroups列,与 id 列进行交叉连接。

于 2013-07-30T23:58:31.237 回答