代码之家  ›  专栏  ›  技术社区  ›  Aman

检查Postgres表中是否存在记录

  •  1
  • Aman  · 技术社区  · 13 年前

    我必须每20秒读一次CSV。每个CSV包含最少500到最多60000行。我必须在Postgres表中插入数据,但在此之前,我需要检查项目是否已经插入,因为很有可能得到重复的项目。要检查唯一性的字段也会编制索引。

    因此,我分块读取文件,并使用in子句来获取数据库中已经存在的项。

    有更好的方法吗?

    2 回复  |  直到 9 年前
        1
  •  3
  •   Community Mohan Dere    9 年前

    这应该表现良好:

    CREATE TEMP TABLE tmp AS SELECT * FROM tbl LIMIT 0 -- copy layout, but no data
    
    COPY tmp FROM '/absolute/path/to/file' FORMAT csv;
    
    INSERT INTO tbl
    SELECT tmp.*
    FROM   tmp
    LEFT   JOIN tbl USING (tbl_id)
    WHERE  tbl.tbl_id IS NULL;
    
    DROP TABLE tmp; -- else dropped at end of session automatically
    

    与密切相关 this answer

        2
  •  1
  •   Clodoaldo Neto    13 年前

    首先,为了完整起见,我将欧文的代码改为使用 except

    CREATE TEMP TABLE tmp AS SELECT * FROM tbl LIMIT 0 -- copy layout, but no data
    COPY tmp FROM '/absolute/path/to/file' FORMAT csv;
    
    INSERT INTO tbl
    SELECT tmp.*
    FROM   tmp
    except
    select *
    from tbl
    
    DROP TABLE tmp;
    

    然后我决定自己测试一下。我在9.1中测试了它,基本上没有受到影响 postgresql.conf 目标表包含1000万行,原始表包含3万行。目标表中已存在15000个。

    create table tbl (id integer primary key)
    ;
    insert into tbl
    select generate_series(1, 10000000)
    ;
    create temp table tmp as select * from tbl limit 0
    ;
    insert into tmp
    select generate_series(9985000, 10015000)
    ;
    

    我只要求对选定部分进行解释。这个 除了 版本:

    explain
    select *
    from tmp
    except
    select *
    from tbl
    ;
                                           QUERY PLAN                                       
    ----------------------------------------------------------------------------------------
     HashSetOp Except  (cost=0.00..270098.68 rows=200 width=4)
       ->  Append  (cost=0.00..245018.94 rows=10031897 width=4)
             ->  Subquery Scan on "*SELECT* 1"  (cost=0.00..771.40 rows=31920 width=4)
                   ->  Seq Scan on tmp  (cost=0.00..452.20 rows=31920 width=4)
             ->  Subquery Scan on "*SELECT* 2"  (cost=0.00..244247.54 rows=9999977 width=4)
                   ->  Seq Scan on tbl  (cost=0.00..144247.77 rows=9999977 width=4)
    (6 rows)
    

    这个 outer join 版本:

    explain
    select *
    from 
        tmp
        left join
        tbl using (id)
    where tbl.id is null
    ;
                                    QUERY PLAN                                
    --------------------------------------------------------------------------
     Nested Loop Anti Join  (cost=0.00..208142.58 rows=15960 width=4)
       ->  Seq Scan on tmp  (cost=0.00..452.20 rows=31920 width=4)
       ->  Index Scan using tbl_pkey on tbl  (cost=0.00..7.80 rows=1 width=4)
             Index Cond: (tmp.id = id)
    (4 rows)