首先,我想強調的是,尋找最有效的查詢是一個很好的查詢和的良好指標的組合。我經常在這裏看到一些問題,人們只在其中一方尋找魔法。
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 –