ちょっと難しい 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 |
基本的に、この手順では、最初に任意のセッションの最新のページビューを取得し、それをテーブルに挿入してから、すべてのセッションが完了するまで繰り返しバックトラックします。
言うまでもなく、これは信じられないほど遅いです。誰でもより良い解決策、できれば1つのクエリのみを含む解決策を持っていますか?