使这个SQLite查询更有效

时间:2013-01-20 19:55:55

标签: sqlite android-sqlite

我开发了一款Android应用,允许用户以各种方式观看电视指南。其中一个视图是一个Now / Next视图,它基本上是一个带有分隔符(显示频道名称)的列表,每个分隔符后跟当前/下一个电视节目详细信息。

我遇到的问题是测试我自己的67个频道阵容需要20-30秒来生成视图(移动应用程序非常慢)我知道我的一些用户有~200 +信道。

我用来获取1个通道的Now / Next详细信息的SQL查询如下...

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

对于我只想拉2条记录的查询看起来相当复杂,其中第一条记录的开始时间在当前时间之前(或等于)当前时间之前,结束时间在当前时间之后(现在),第二条记录有与第一个(下一个)的结束时间匹配的开始时间。

我只是想知道是否有更有效的方法来查询这种情况。

使用以下内容创建epg_event表(为了说明架构)...

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)
)

显示的查询将返回...

_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

1 个答案:

答案 0 :(得分:1)

据我所知,你的查询的这一部分应该是任何仍然播出或尚未播出的节目:

    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

但是,这两个条件相当于show尚未结束的条件,或者:

    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

现在,在这里您按已知的channel_oid进行过滤,然而GROUP BY为什么?它应简化为

    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

据我所知,您最好用datetime('now')替换CURRENT_TIMESTAMP。这会产生最终的SQL:

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

要使其快速运行,请确保创建正确的索引。 This answer可以为您提供一些如何优化它的建议,但首先,您应该在epg_event表上至少包含以下复合索引:(channel_oid, start_time)(channel_oid, end_time)