首先,我想强调的是,寻找最有效的查询是一个很好的查询和的良好指标的组合。我经常在这里看到一些问题,人们只在其中一方寻找魔法。
E.g.在各种解决方案中,当没有索引时,您的速度最慢(在修复语法错误之后),但在索引上更好一些(detail, order_id)
请注意,您拥有实际的数据和表结构。您需要尝试各种查询和索引组合以找到最佳效果;不仅仅是因为你没有指出你使用的平台,结果可能会因平台而异。
[/ ranf断]
查询
事不宜迟,戈登·利诺夫已经提供了一些良好suggestions。还有另一种选择可能会提供类似的表现。你说你不能控制模式;但是您可以使用子查询将数据转换为“友好结构”。
具体来说,如果您:
- 支点的数据,所以你必须每
order_id
- 和列一排的每个
detail
要检查
- 和路口是多少订单的数量有那个细节...
然后你的查询很简单:where (x=0 or y=0) and (a=0 or b=0)
。以下使用SQL Server的临时表来演示示例数据。下面的查询不管重复id, val
对。
/*Set up sample data*/
declare @t table (
id int,
val char(1)
)
insert @t(id, val)
values (1, 'x'), (1, 'y'), (1, 'z'),
(2, 'x'), (2, 'z'), (2, 'b'),
(3, 'a'), (3, 'z'), (3, 'b')
/*Option 1 manual pivoting*/
select t.id
from (
select o.id,
sum(case when o.val = 'a' then 1 else 0 end) as a,
sum(case when o.val = 'b' then 1 else 0 end) as b,
sum(case when o.val = 'x' then 1 else 0 end) as x,
sum(case when o.val = 'y' then 1 else 0 end) as y
from @t o
group by o.id
) t
where (x = 0 or y = 0) and (a = 0 or b = 0)
/*Option 2 using Sql Server PIVOT feature*/
select t.id
from (
select id ,[a],[b],[x],[y]
from (select id, val from @t) src
pivot (count(val) for val in ([a],[b],[x],[y])) pvt
) t
where (x = 0 or y = 0) and (a = 0 or b = 0)
有趣的是,上面的选项1和2的查询计划略有不同。这表明与大型数据集不同的性能特征的可能性。
指标
注意上面可能会处理整个表。所以从索引中获得的东西很少。但是,如果表格有“长行”,那么仅处理2列的索引意味着需要从磁盘读取更少的数据。
您提供的查询结构可能受益于诸如(detail, order_id)
之类的索引。这是因为服务器可以更有效地检查NOT IN
子查询条件。如何受益取决于表中数据的分布。
作为一个便笺,我测试了各种查询选项,包括您的和戈登的固定版本。 (尽管只有很小的数据大小)
- 没有上述索引,您的查询在批处理中是最慢的。
- 有了上述指标,Gordon的第二个查询是最慢的。
的替代查询
您的查询(固定):戈登的第一和第二查询之间
select distinct o.id
from @t o
where o.id not in (
select od1.id
from @t od1
inner join @t od2 on
od2.id = od1.id
and od2.val='Y'
where od1.val= 'X'
)
and o.id not in (
select od1.id
from @t od1
inner join @t od2 on
od2.id = od1.id
and od2.val='a'
where od1.val= 'b'
)
混合物。修复了第一个重复的问题,并在第二个表现:
select id
from @t od
group by id
having ( sum(case when val in ('X') then 1 else 0 end) = 0
or sum(case when val in ('Y') then 1 else 0 end) = 0
)
and( sum(case when val in ('A') then 1 else 0 end) = 0
or sum(case when val in ('B') then 1 else 0 end) = 0
)
使用INTERSECT和EXCEPT:
select id
from @t
except
(
select id
from @t
where val = 'a'
intersect
select id
from @t
where val = 'b'
)
except
(
select id
from @t
where val = 'x'
intersect
select id
from @t
where val = 'y'
)
子查询内部的不同是无用的,可能不是你的DBMS –