查询优化,摆脱子查询

时间:2015-02-09 19:29:34

标签: sql sqlite

我正在使用sqlite3,但它的SQL支持相当标准,因此只要SQL不包含任何专有扩展,所有都应该是好的。我的架构如下:

create table test (
    _id integer primary key,
    name text, 
    enabled integer not null default 1
);
create table task (
    _id integer primary key, 
    _test_id integer not null references test on delete cascade, 
    favorite integer not null default 0,
    comment text
);

简而言之:有些测试可以启用或不启用;测试有多个任务,可以是最喜欢的,也可能有评论。

我需要编写的两个最复杂的查询如下:

  • 一个select,用于检索数据库是否包含至少1个收藏夹和至少1个已启用测试的评论任务(即不按测试分组)。我想出了以下怪物:

    select
      exists(select task._id from task as task inner join test as test on task._test_id=test._id where task.favorite=1 and test.enabled=1 limit 1) as has_favorite,
      exists(select task._id from task as task inner join test as test on task._test_id=test._id where task.comment is not null and test.enabled=1 limit 1) as has_commented;
    
  • 一个select,它检索测试核心数据(id,name等)以及有关其任务计数的信息,测试是否包含至少1个收藏夹和至少1个评论任务。我想出了这个:

    select
        test.*,
        (select count(*) from task where _test_id=test._id) as task_count,
        exists(select _id from task where favorite=1 and _test_id=test._id limit 1) as has_favorite,
        exists(select _id from task where comment is not null and _test_id=test._id limit 1) as has_commented
    from test as test where test.enabled=1 order by test._id asc
    

实际上,'has_favorite'和'has_commented'信息并不是唯一的,但是它们描述了我的怀疑 - 这些查询非常大,包含相当数量的子查询(并且我读取子选择对性能不利)和重复

问题:是否可以更轻松地编写查询?让它们变得更好,更简洁?不重复那么多?例如,我想也许有办法在任务和测试表之间只执行一次连接,并以某种方式从那里派生数据。

编辑:所以看来我可以为第一个写这个:

    select
        count(*) as task_count,
        max(task.favorite) as has_favorite,
        count(task.comment) as has_commented
    from task as task inner join test as test on task._test_id=test._id where test.enabled=1;

这是第二个:

select
    test.*,
    count(*) as task_count,
    max(task.favorite) as has_favorite,
    count(task.comment) as has_commented
from task as task inner join test as test on task._test_id=test._id where test.enabled=1 group by test._id;

如果max(task.favorite)是什么> 0表示至少有1个任务是最喜欢的。我可以用'sum(task.favorite)'代替它,如果总和> 0,有一个最爱。

这是否比原始提案(存在(subselect))更好?这似乎更容易。

1 个答案:

答案 0 :(得分:0)

我最终加入了类似于我编辑中的连接,因为它们工作得非常好,也允许一次性收集其他信息。