查找dense_rank的最佳查询以查找倍数

时间:2016-09-20 21:34:47

标签: sql postgresql query-optimization

我正在查询网络流量架构,以确定哪些访问是初始访问,哪些是返回。

我有两个表SESSION和ALIAS。

CREATE TABLE alias (
  person_id vachar(24),
  alias varchar(24)
)

CREATE TABLE session (
  session_id vachar(24),
  alias varchar(24)  -- FK to alias
  last_seen timestamp
)

会话表表示别名的Web访问,别名表包含人员的别名。我尝试在会话上创建一个视图,允许我将会话标记为" First Visit" 由某人或"返回访问" 由某人(因此加入以下别名)。

我到目前为止的解决方案是使用一个带有dense_rank的窗口函数,如下所示。

CREATE VIEW session_augmented as (
    SELECT S.session_id, S.last_seen, ....
     CASE 
        WHEN dense_rank() 
            OVER (partition by A.person_id COLLATE "C" ORDER by S.last_seen ) = 1 
        THEN 'First Visit' 
        ELSE 'Return Visit' 
     END as visit_type
    FROM session S
    JOIN alias A ON (S.person_alias = A.alias)

)

我创建了涵盖查询范围的索引,包括上面的连接。

即使对person_alias列编制索引,下面的说明也会显示会话中的Seq Scan。以下是解释: https://explain.depesz.com/s/2LJ

查询运行速度比我想慢,是否有优化方法?是否有更好的方法可以实现我之后的结果?

1 个答案:

答案 0 :(得分:1)

Rank,Dense Rank和涉及排序的任何事情将是平均情况 O(n log n),对于非常大的数据集来说,它可能变得非常压抑。在这种情况下,我认为你可以使用b解析函数,这应该是最好,最差和平均情况 O(n)

min

虽然我怀疑这对你描述的情况很重要,但如果一个人在理论上可以在同一时间登录两次,那么这将失败,因为它将返回两个记录。也就是说,你的查询会遇到同样的问题,而且我认为它甚至不可能 - 我只是认为我会引起你的注意。

对于值得窗口的功能来说绝对是最佳选择。我看到的唯一理智的选择是用一些编程语言编写一个包装器。我怀疑你会看到SELECT S.session_id, S.last_seen, .... CASE WHEN min (S.last_seen) over (partition by a.person_id) = s.last_seen THEN 'First Visit' ELSE 'Return Visit' END as visit_type FROM session S JOIN alias A ON (S.person_alias = A.alias) 函数的改进。