加快SQLite查询,我可以在没有联合的情况下完成吗?

时间:2012-03-25 08:13:13

标签: sql sqlite

大家都知道stackoverflow社区!我已经访问这个网站多年了,这是我的第一篇文章

假设我有一个包含三个表的数据库:

  • 组(GroupID,GroupType,max1,size)
  • 糖果(candyID,名字,精选)
  • 成员(groupID,nameID)

示例:糖果工厂。
在糖果工厂,80种不同的糖果生产了10种糖果袋。

所以:有10种独特的群体类型(袋子),有3种不同的尺寸:(4,5,6);一组是80种独特糖果的组合。

出于这个原因,我创建了一个数据库,(有一些关于哪些糖果组合进入一个组的规则)。

此时我有一个包含40791个独特糖果袋的数据库。

现在我想将一系列糖果与数据库中的所有糖果袋进行比较,结果我想要从数据库中取出的袋子与比较系列中缺少3个或更少的糖果。

-- restore candy status
update candies set selected = 0, blacklisted = 0;

-- set status for candies to be selected
update candies set selected = 1 where name in ('candy01','candy02','candy03','candy04');

select  groupId, GroupType, max, count(*) as remainingNum, group_concat(name,', ') as remaining
from groups natural join members natural join candies
where not selected 
group by groupid having  count(*) <= 3

UNION -- Union with groups which dont have any remaining candies and have a 100% match

select groupid, GroupType, max,  0 as remainingNum, "" as remaining
from groups natural join members natural join candies
where selected 
group by groupid having count(*) =groups.size;

以上查询执行此操作。但我想要完成的是在没有结合的情况下做到这一点,因为速度是至关重要的。而且我也是sql的新手,非常渴望学习/看到新的方法。

问候,Rutger

2 个答案:

答案 0 :(得分:3)

我不是100%肯定你通过这些查询完成了什么,所以我没有看到一个根本不同的方法。如果您可以包含示例数据来演示您的逻辑,我可以看一下。但是,就简单地组合你的两个查询而言,我可以做到这一点。首先要注意一点,但是......

SQL被编译到查询计划中。如果每个查询的查询计划与另一个查询的显着不同,将它们组合到单个查询中可能是个坏主意。您可能最终得到的是一个适用于这两种情况的单一计划,但对两者都不是很有效。一个糟糕的计划可能比两个好计划更糟糕=&gt;更短,更紧凑的代码并不总能提供更快的代码。


您可以将selected放入GROUP BY而不是WHERE条款中;您有两个UNIONed个查询这一事实表明您已将它们视为两个独立的组。

然后,您的查询之间的唯一区别是count(*)上的过滤器,您可以使用CASE WHEN语句来容纳...

SELECT
  groups.groupID,
  groups.GroupType,
  groups.max,
  CASE WHEN Candies.Selected = 0 THEN count(*)  ELSE 0 END as remainingNum,
  CASE WHEN Candies.Selected = 0 THEN group_concat(candies.name,', ') ELSE '' END as remaining
FROM
  groups
INNER JOIN
  members
    ON members.GroupID = groups.GroupID
INNER JOIN
  candies
    ON Candies.CandyID = members.CandyID
GROUP BY
  Groups.GroupID,
  Groups.GroupType,
  Groups.max,
  Candies.Selected
HAVING
  CASE
    WHEN Candies.Selected = 0 AND COUNT(*) <= 3           THEN 1
    WHEN Candies.Selected = 1 AND COUNT(*)  = Groups.Size THEN 1
                                                          ELSE 0
  END
  =
  1

布局更改只是因为出于维护原因我不同意使用NATURAL JOIN。它们是初始构建的捷径,也是后期开发中的潜在灾难。但这是一个不同的问题,如果您愿意,可以在线阅读。

答案 1 :(得分:0)

在进行选择时不要更新数据库,第一次更新update candies set selected = 0, blacklisted = 0;将应用于整个表,并重写每条记录。您应该尝试不使用selected并将联盟更改为UNION ALL。除此之外,您还尝试使用内部联接而不是自然联接(但我不知道您对成员的糖果架构)

select  groupId, GroupType, max, count(*) as remainingNum, group_concat(name,', ') as remaining
from groups 
    inner join members on members.groupid = groups.groupid
    inner join candies on candies.candyid = member.candyid
where name NOT in ('candy01','candy02','candy03','candy04')
group by groups.groupid
having  count(*) <= 3

UNION ALL -- Union with groups which dont have any remaining candies and have a 100% match

select groupid, GroupType, max,  0 as remainingNum, "" as remaining
from groups 
    inner join members on members.groupid = groups.groupid
    inner join candies on candies.candyid = member.candyid
where name in ('candy01','candy02','candy03','candy04')
group by groupid
having count(*) = groups.size;

这至少应该比在查询表中更新表中的所有记录更好。