使用row_number()

时间:2018-03-17 15:44:30

标签: sql postgresql

假设有一个表客户,它有以下列:

  • customer_id作为主键

  • CREATION_DATE

  • 几乎没有其他专栏

我想使用creation_date> = to_date(' 2000/01 / 01',' YYYY / MM / DD')查询customers表中的所有条目并插入另一个表客户。 表客户中的条目数约为1000万,并且这两个表都在同一个数据库中。 我想尽量减少复制此数据的时间。

有两种方法:

  1. 对每个n并行运行以下查询,n = 1,10001,20001 ......等等

    insert into clients 
    values ( 
      select * 
      from ( 
        select *, row_number() over (ORDER BY customer_id) as rn 
        from ( 
          select * 
          from customers 
          where creation_date >= to_date('2000/01/01', 'YYYY/MM/DD')
        ) as sub1
      ) as sub2  
      where rn>=n limit 10000
    );
    
  2. 运行单个查询

    insert into clients 
    values ( 
      select * 
      from customers 
      where creation_date >= to_date('2000/01/01', 'YYYY/MM/DD')
    );
    
  3. 对于1,以下是执行计划

    
        Insert on clients  (cost=0.42..113.55 rows=10000 width=4506)
           ->  Subquery Scan on "*SELECT*"  (cost=0.42..113.55 rows=10000 width=4506)
                 ->  Limit  (cost=0.42..112.45 rows=10000 width=616)
                       ->  Subquery Scan on sub2  (cost=0.42..57773.19 rows=1000000 width=616)
                             Filter: (sub2.rn >= 0)
                             ->  WindowAgg  (cost=0.42..57579.79 rows=1000000 width=624)
                                   ->  Index Scan using “customer_id_pkey" on customers (cost=0.42..57347.71 rows=1000000 width=616)
                                         Filter: ((creation_date >= to_date('2000/01/01'::text, 'YYYY/MM/DD'::text)) 
    
    

    对于所有并行执行, sub2 上的子查询扫描将对整个数据运行。因此,并行执行已经打败了目的。

    我的理解是正确的还是接近1会比接近2更少的时间。

    另外请建议是否有办法提高查询性能。

    [计划节点的值已被修改,因此请忽略行,成本和宽度值]

1 个答案:

答案 0 :(得分:0)

这更像是一个扩展评论。

你应该尝试不同的方法,看看哪种方法效果最好。就个人而言,我会采用第二种方法,尽管我会把它写成:

insert into clients ( . . .)
    select c.*
    from customers c
    where creation_date >= date '2000-01-01';

为什么呢?在表中执行多个insert会生成表争用,日志争用和可能的索引争用。这可能会减慢速度。我不是说它会 - 只是不考虑它,我只是开始查询并等待它需要多长时间(一杯咖啡?午餐?过夜?)

如果您的数据非常大,那么您可能想要考虑对数据进行分区。如果是这种情况,那么多个同时插入是个好主意 - 只要它们都进入单个分区。

顺便说一句,在您的第一个版本中,您不需要使用row_number()。您可以使用offset / fetch语法来获取不同的数据。