我尝试用(user1,user2,count)创建一个新表,以表示两个用户在一小时间隔内在一列中共享相同值的时间。
WITH d1 AS (SELECT * FROM user_access_tab
WHERE last_access >= 1544630400 AND last_access <= 1545601214)
SELECT d1.userid, d2.userid, COUNT(*) as count
FROM d1
INNER JOIN d1 AS d2
ON d1.item = d2.item AND d1.userid != d2.userid
WHERE d1.last_access < d2.last_access AND
(d2.last_access - d1.last_access) <= 3600
GROUP BY d1.userid, d2.userid
但是,即使间隔时间限制为1小时,此类查询也非常慢。我需要查询大约6个月的数据,这些数据已累积到数十亿行记录。如何改善SQL?
user_access_tab如下所示
新表格如下所示。只要两个用户ID的last_access在1小时窗口内,它们就会链接在一起,并且计数器增加1。
答案 0 :(得分:0)
恕我直言,您查询的问题是您之间的记录太多了。
以下面的最小示例为例,我插入了CTE:
WITH user_access_tab(item, userid, last_access) AS (
SELECT UNNEST(ARRAY['A', 'A', 'A', 'A', 'A', 'A']),
UNNEST(ARRAY[11383575,11383575,52539489,52539489,24830131,24830131]),
UNNEST(ARRAY[1545645324,1545645325,1545647895,1545647896,1545646895,1545646896])
/*UNION ALL
SELECT UNNEST(ARRAY['A', 'A', 'A', 'A', 'A', 'A']),
UNNEST(ARRAY[11383575,11383575,52539489,52539489,24830131,24830131]),
UNNEST(ARRAY[1545645326,1545645327,1545647897,1545647898,1545646897,1545646898])*/
),
d1 AS (SELECT * FROM user_access_tab
WHERE last_access >= 1544630400 AND last_access <= 1545661214
)
SELECT d1.userid, d2.userid, COUNT(*) as count
FROM d1
INNER JOIN d1 AS d2
ON d1.item = d2.item AND d1.userid != d2.userid
WHERE d1.last_access < d2.last_access AND
(d2.last_access - d1.last_access) <= 3600
GROUP BY d1.userid, d2.userid
CTE有6条记录,查询返回3条记录,每条记录的计数等于4。
现在取消注释CTE的后半部分,您得到的是3x16。这比CTE中的记录数还多,并且只有随着更多的用户和事件而变得更糟。
我建议您在JOIN
的一侧做一些更严格的限制。下面的示例:
WITH d1 AS (SELECT * FROM user_access_tab
WHERE last_access >= 1544630400 AND last_access <= 1545661214),
d2 AS (
SELECT *
FROM d1 d
WHERE NOT EXISTS (SELECT FROM d1 WHERE item = d.item AND userid = d.userid AND d.last_access BETWEEN last_access+1 AND d.last_access + 3600))
SELECT d2.item, d2.userid, d1.userid, COUNT(*)
FROM d2
LEFT OUTER JOIN d1 ON d2.item = d1.item AND d2.userid = d1.userid AND d1.last_access BETWEEN d2.last_access and d2.last_access + 3600
GROUP BY d2.item, d2.userid, d1.userid
很明显,这将更改COUNT(*)
列中的结果(除了要更快),但是由于以前似乎没有多大意义,所以我认为这是最好的。