Reputation: 48871
I develop an Android app which allows a user to view a TV Guide in various ways. One of the views is a Now/Next view which is basically a list with separators (showing channel names) with each separator followed by the current / next TV show details.
The problem I'm having is with testing my own line-up of 67 channels it takes anything from 20-30 seconds to generate the view (horribly slow for mobile apps) and I know some of my users have ~200+ channels.
The SQL query I use to get the Now/Next details for 1 channel is as follows...
SELECT
b.oid AS _id,
b.channel_oid,
b.title,
b.start_time,
b.end_time
FROM epg_event b,
(
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.start_time > datetime('now')
AND a.channel_oid = 10029
GROUP BY a.channel_oid
UNION
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.start_time <= datetime('now')
AND a.end_time > datetime('now')
AND a.channel_oid = 10029
GROUP BY a.channel_oid
) c
WHERE c.start_time = b.start_time
AND c.channel_oid = b.channel_oid
ORDER BY b.start_time
That seems pretty complex for a query where I just want to pull 2 records where the start time of the first is before (or equal to) the current time and end time is after current time (Now) and the second record has a start time which matches the end time of the first (Next).
I'm just wondering if there is a more efficient way to query for this sort of scenario.
The epg_event table is created with the following (in order to illustrate the schema)...
CREATE TABLE [EPG_EVENT] (
[oid] integer PRIMARY KEY,
[title] varchar(50),
[subtitle] varchar(50),
[description] varchar(50),
[start_time] datetime,
[end_time] datetime,
[channel_oid] int,
[unique_id] varchar(50),
[rating] varchar(50),
[original_air_date] datetime,
[season] int,
[episode] int,
[dvb_service_event_id] int,
[dvb_table_version] int,
[genres] varchar(50)
)
The query shown will return...
_id, channel_oid, title, start_time, end_time
10467376, 10029, Ripper Street, 2013-01-20 21:00:00, 2013-01-20 22:00:00
10467377, 10029, BBC News; Regional News and Weather, 2013-01-20 22:00:00, 2013-01-20 22:25:00
Upvotes: 0
Views: 288
Reputation: 116177
As far as I can tell, this part of your query is supposed to get any show that either still being aired or has not started yet:
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.start_time > datetime('now')
AND a.channel_oid = 10029
GROUP BY a.channel_oid
UNION
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.start_time <= datetime('now')
AND a.end_time > datetime('now')
AND a.channel_oid = 10029
GROUP BY a.channel_oid
But, these 2 conditions are equivalent to condition that show has not ended yet, or to:
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.end_time > datetime('now')
AND a.channel_oid = 10029
GROUP BY a.channel_oid
Now, here you filter by known channel_oid and yet GROUP BY
it - why? It should be simplified as
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.end_time > datetime('now')
AND a.channel_oid = 10029
As far as I can tell, you are probably better off replacing datetime('now')
with CURRENT_TIMESTAMP
. This yields your final SQL as:
SELECT
b.oid AS _id,
b.channel_oid,
b.title,
b.start_time,
b.end_time
FROM epg_event b,
(
SELECT
MIN(a.start_time) AS start_time,
a.channel_oid,
a.end_time
FROM epg_event a
WHERE a.end_time > CURRENT_TIMESTAMP
AND a.channel_oid = 10029
) c
WHERE c.start_time = b.start_time
AND c.channel_oid = b.channel_oid
ORDER BY b.start_time
To make it work fast, make sure to create proper indexes. This answer can give you some ideas how to optimize it, but on first look, you should have at least following compound indexes on epg_event
table: (channel_oid, start_time)
and (channel_oid, end_time)
.
Upvotes: 1