【问题标题】:How to optimize selection of pairs from one column of the table?如何优化从表的一列中选择对?
【发布时间】:2020-04-09 18:17:16
【问题描述】:

我使用的是 PostgreSQL 9.5.19、DBeaver 6.3.4

我有一张桌子,其中一行是 - 用户名、他参加的地点、他在那里的时间

我需要选择任何用户所在的所有地点对(如果用户在地点 a 和地点 b,我需要这样的行:用户、地点 a、地点 b、地点 a 的时间、地点 b 的时间)

池塘桌:

CREATE TABLE example.example (
    tm timestamp NOT NULL,
    place_name varchar NOT NULL,
    user_name varchar NOT NULL
);

一些样本数据:

INSERT INTO example.example (tm, place_name, user_name)
values
('2020-02-25 00:00:19.000', 'place_1', 'user_1'),
('2020-03-25 00:00:19.000', 'place_2', 'user_1'),
('2020-02-25 00:00:19.000', 'place_1', 'user_2'),
('2020-03-25 00:00:19.000', 'place_1', 'user_3'),
('2020-02-25 00:00:19.000', 'place_2', 'user_3');

我正在尝试这个脚本:

select 
   t.user_name    
  ,t.place_name as r1_place
  ,max(t.tm) as r1_tm
  ,t2.place_name as r2_place
  ,min(t2.tm) as r2_tm
from example.example as t
join example.example as t2 on t.user_name = t2.user_name 
                       and t.tm < t2.tm 
                       and t.place_name <> t2.place_name
where t.tm between '2020-02-25 00:00:00' and '2020-03-25 15:00:00' 
  and t2.tm between '2020-02-25 00:00:00' and '2020-03-25 15:00:00'
    group by t.user_name
       , t.place_name
       , t2.place_name

似乎它给了我正确的结果,但它的工作速度真的很慢。 我可以以某种方式优化它吗?

【问题讨论】:

  • 您希望数据中每个用户有多少行?结果集中有多少个?
  • 取决于他参加过的地方的数量。现在有 5 个地方,所以如果用户在所有地方,我猜结果是 5^5 =at leat 25 行(如果他返回,我们有另一行有这个用户和地方,但有另一个时间)。用户数量也在增加

标签: sql postgresql join optimization


【解决方案1】:

我建议尝试索引。对于这个查询:

select t.user_name, t.place_name as r1_place, max(t.tm) as r1_tm,
       t2.place_name as r2_place, min(t2.tm) as r2_tm
from schema.table t join
     schema.table t2
     on t.user_name = t2.user_name and
        t.tm < t2.tm and
        t.place_name <> t2.place_name
where t.tm between '2020-03-25 00:00:00' and '2020-03-25 15:00:00' and
      t2.tm between '2020-03-25 00:00:00' and '2020-03-25 15:00:00'
group by t.user_name, t.place_name, t2.place_name

我建议在(tm, user_name, place_name)(user_name, tm, place_name) 上建立一个索引——是的,两者都有一个索引。

【讨论】:

    【解决方案2】:

    同事帮我创建了窗口函数:

    select 
    subq.*
    ,EXTRACT(EPOCH FROM (subq.next_tm - subq.tm)) as seconds_diff
    from (
      select
        t1.user_name,
        t1.place_name,
        t1.tm,
        lead(t1.place_name) over w as next_place_name,
        lead(t1.tm) over w as next_tm
      from example.example as t1
      window w as (partition by t1.user_name order by tm asc)
    )subq
    where
      next_place_name is not null
      and next_tm is not null
      and place_name <> next_place_name
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      • 1970-01-01
      • 2012-01-05
      • 1970-01-01
      • 2015-02-03
      • 2021-06-11
      相关资源
      最近更新 更多