ИМХО, проблема с вашим запросом состоит в том, что вы объединяете слишком много записей друг с другом.
Возьмите приведенный ниже минимальный пример, где я вставил 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, и оно только ухудшается с увеличением количества пользователей и событий.
Я бы посоветовал вам сделать что-то более ограничительное с 1 стороны вашей 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(*)
(в дополнение к тому, что он быстрее), но так как раньше он не имел особого смысла, я бы сказал, что это длялучший.