我正在查询网络流量架构,以确定哪些访问是初始访问,哪些是返回。
我有两个表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
查询运行速度比我想慢,是否有优化方法?是否有更好的方法可以实现我之后的结果?
答案 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)
函数的改进。