【问题标题】:Filter only Value Changes in a postgres table仅过滤 postgres 表中的值更改
【发布时间】:2016-12-23 12:18:15
【问题描述】:

我有一个非常特殊的问题。我有一个 4400 万条记录表如下:

SKU | Timestamp           | Status
A   | 21-09-2016 12:30:00 | 1  
B   | 21-09-2016 12:30:00 | 1  
C   | 21-09-2016 12:30:00 | 1  
D   | 21-09-2016 12:30:00 | 1  
A   | 21-09-2016 12:39:00 | 0  
B   | 21-09-2016 12:40:00 | 0  
C   | 21-09-2016 12:40:00 | 0  
D   | 21-09-2016 12:45:00 | 0  
A   | 21-09-2016 12:52:00 | 1  
A   | 21-09-2016 12:56:00 | 1  
A   | 21-09-2016 12:58:00 | 1  
B   | 21-09-2016 12:59:00 | 1  
A   | 21-09-2016 21:30:00 | 0  

现在的要求是我们应该只考虑状态发生变化的记录。例如上表中,SKU A 在 21-09-2016 12:30:00 以状态 1 开始。我们现在查看未来的记录并查看记录何时更改,因此下一次更改将在 21-09-2016 21:30:00 状态变为 0 时看到。现在我们需要一个具有以下输出的表

SKU | Timestamp           | Status
A   | 21-09-2016 12:30:00 | 1  
A   | 21-09-2016 12:39:00 | 0  
A   | 21-09-2016 12:52:00 | 1  
A   | 21-09-2016 21:30:00 | 0  
B   | 21-09-2016 12:30:00 | 1  
B   | 21-09-2016 12:40:00 | 0  
B   | 21-09-2016 12:59:00 | 1  
C   | 21-09-2016 12:30:00 | 1  
C   | 21-09-2016 12:40:00 | 0  
D   | 21-09-2016 12:30:00 | 1  
D   | 21-09-2016 12:45:00 | 0  

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:
    select sku, timestamp, status
    from (
        select *, lag(status) over (partition by sku order by timestamp) as prev_status
        from example
        ) s
    where prev_status is distinct from status;
    

    Test it here.

    【讨论】:

      【解决方案2】:

      我想你想要lag():

      select t.*
      from (select t.*,
                   lag(status) over (partition by sku order by timestamp) as prev_status
            from t
           ) t
      where (prev_status is distinct from status) ;
      

      注意:is distinct from 很像 <>,但它更直观地处理 NULL 值。

      【讨论】:

      • 嗨,戈登,感谢您的回答。在 4400 万条记录表中,我们预计这需要多少时间/
      • @SaurabhOmar 。 . . (sku, timestamp, status) 上的索引应该有助于加快查询速度。
      【解决方案3】:

      除了克林和戈登的回答和回答

      在 4400 万条记录表中,我们预计这需要多长时间

      这在很大程度上取决于 PostgreSQL 可用的 RAM。因为子查询的结果应该存储在某个地方(然后再次扫描)。

      如果 RAM 量足以存储中间结果 - 那么一切都好,如果没有 - 你就麻烦了。

      例如,在我对包含 10,000,000 行的表进行测试时,我在等待超过 15 分钟后取消了普通查询。

      或者,使用存储函数,它在大约 4 分钟内完成,这与简单的有序选择(大约 2 分钟)相比并不多。

      这是我的测试:

      -- Create data
      
      --drop function if exists foo();
      --drop table if exists test;
      create table test (i bigserial primary key, sku char(1), ts timestamp, status smallint);
      
      insert into test (sku, ts, status) 
        select
          chr(ascii('A') + (random()*3)::int),
          now()::date + ((random()*100)::int || ' minutes')::interval,
          (random()::int)
        from generate_series(1,10000000);
      
      create index idx on test(sku, ts);
      
      analyse test;
      
      -- And function
      
      create or replace function foo() returns setof test language plpgsql as $$
      declare 
        r test;
        p test;
      begin
        for r in select * from test order by sku, ts loop
          if p.status is distinct from r.status or p.sku is distinct from r.sku then
            return next r;
          end if;
          p := r;
        end loop;
        return;
      end $$;
      
      -- Test queries
      
      explain (analyse, verbose) 
      select i, sku, ts, status
      from (
          select *, lag(status) over (partition by sku order by ts) as prev_status
          from test
          ) s
      where prev_status is distinct from status;
      -- Not completed, still working after ~ 15 min
      
      explain analyse select * from test order by sku, ts;
      -- Complete in ~2 min
      
      explain (analyse, verbose) select * from foo();
      -- Complete in ~3:30 min 
      

      【讨论】:

      猜你喜欢
      • 2021-12-31
      • 2020-12-20
      • 1970-01-01
      • 1970-01-01
      • 2023-02-06
      • 1970-01-01
      • 2017-11-25
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多