我有一个具有挑战性的 SQL 问题:假设您有一个页面浏览量表,如下所示:
CREATE TABLE pageviews (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) NOT NULL,
timestamp DATETIME NOT NULL,
PRIMARY KEY (id)
)
在此表中,您有大量记录(> 1 亿)。从这些数据中,您想要生成另一个如下所示的表:
CREATE TABLE sessions (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) NOT NULL,
started_at DATETIME NOT NULL,
ended_at DATETIME NOT NULL,
PRIMARY KEY (id)
)
规则是会话是任意数量的浏览量的任意序列,其中不包含任何大于 30 分钟的间隔。
现在我已经设法使用一个使用循环来获取会话的存储过程来生成这个表:
DELIMITER |
CREATE PROCEDURE generate_sessions()
BEGIN
TRUNCATE sessions;
INSERT INTO sessions
SELECT NULL, p.user_id, p.timestamp, p.timestamp FROM pageviews p
LEFT JOIN pageviews2 p2 ON p2.user_id = p.user_id AND p2.timestamp > p.timestamp AND p2.timestamp < DATE_ADD(p.timestamp, INTERVAL 30 MINUTE)
WHERE p2.id IS NULL;
REPEAT
UPDATE sessions s
LEFT JOIN pageviews p ON p.user_id = s.user_id AND p.timestamp < s.started_at AND p.timestamp > DATE_SUB(s.started_at, INTERVAL 30 MINUTE)
SET s.started_at = p.timestamp
WHERE p.id IS NOT NULL;
UNTIL ROW_COUNT() = 0 END REPEAT;
END |
基本上,该过程所做的是首先获取任何会话的最新页面浏览量,将其插入表中,然后迭代回溯,直到所有会话完成。
不用说,这非常慢。任何人都有更好的解决方案,最好是只涉及一个查询的解决方案?