Transforming start and end times to simple graph
I've upgraded and worked a bit with CTEs. The following query runs in about half of the time.

WITH RECURSIVE tstamp_cte AS (
    SELECT 0 AS n, CURRENT_TIMESTAMP AS tstamp FROM DUAL
    UNION ALL
    SELECT n + 1, tstamp - INTERVAL 15 MINUTE FROM tstamp_cte WHERE n &lt; 96
)
SELECT tstamp, (SELECT COUNT(*) FROM sessions WHERE starttime &lt; tstamp AND endtime &gt;= tstamp OR endtime IS NULL) AS 'sessionCount'
FROM tstamp_cte