回答

收藏

使用IN(子查询)时,性能损失很大。为什么?

技术问答 技术问答 498 人阅读 | 0 人回复 | 2023-09-12

我正在使用SQL Server 2005,当我想在IN子句中使用子查询时要过滤某些结果时,我注意到了一些奇怪的事情。例如,这是我当前的查询,平均运行70秒:
% K: D: W$ M. K1 t; q7 w! N' Uselect Phone, ZipCode, sum(Calls) as Calls, sum(Sales) as Sales
7 g  r. {+ ~9 w: x& Dfrom Archive ) ~, @2 c. Y! h! e) Q5 Z0 }+ M
where CustomerID = 20
# T! z7 h  D) band ReportDate = '2/3/2011'/ N& D3 c  e" C. [; I# P2 p# ~
and Phone in (; t7 H+ g2 r. B, h/ ?
    select Phone/ k" s8 Z1 I, _
    from PlanDetails
# Y5 ~. a, V* p0 b# }& y( S8 g    where Phone is not null
4 @* g/ \/ h4 u2 x# l) l    and Length is not null0 G2 [, c8 {/ b
    and PlannedImp > 00 F2 j* j- I( Y" P
    and CustomerID = 200 j1 s" F9 U* V$ O) v% H$ V
    and (StatusID  2 and StatusID  7)
1 I, L& e; `5 a) `' t+ `0 q. W    and SubcategoryID = 88
8 L* a( p- A( v# P)
- I3 D! g. |3 _group by Phone, ZipCode
# @, d" X: M0 z; ]" g' ~* j$ \但是,如果我将它们分解为2个独立的查询,则每个查询要花费不到1秒的时间。
! L; a3 ~* e- U- kselect Phone2 D) i' L6 d( ]/ w  l' @* R
from PlanDetails - n# p# y* o2 P5 E' i  q9 _" P( K
where Phone is not null! Q* \7 {, j, a' O! {; j
and Length is not null
/ }- V8 L6 v: G2 H/ h$ a, d( oand PlannedImp > 0
) k! E& E! u% X% |9 b$ \6 `and CustomerID = 20
7 A% t: N' k  [+ k6 A9 d  zand (StatusID  2 and StatusID  7)
) U$ S. b# u' v/ tand SubcategoryID = 88
6 P+ K" W5 k8 K+ A8 k6 ]" }0 s5 }* k0 n
select Phone, ZipCode, sum(Calls) as Calls, sum(Sales) as Sales+ r9 l$ R! `/ q2 f( M4 M" v
from Archive
" Z+ ?1 Y. O1 h. D+ a# K) w- m+ Vwhere CustomerID = 20
, O6 b& R. ~5 `! {0 qand ReportDate = '2/3/2011'; C& r! g* `8 D
group by Phone, ZipCode" m# h; G# x0 ?! l- d; P
最后,如果执行此操作,它将返回与第一个查询相同的结果,但大约需要2-3秒:0 H4 Z4 q1 L7 _7 k* O+ _+ q8 y
select Phone; R: K4 y" x5 E! M4 l. c: A* I0 t
into #tempTable" z; y, U+ G6 t. S( y$ f
from PlanDetails# q5 Z8 H, e( {, w; n3 H
where Phone is not null
! |! T$ I9 \8 Z; C3 Xand Length is not null
+ F4 {  R5 }2 p4 l3 c6 ]+ Yand PlannedImp > 0
: Q$ C. `1 Z$ s' j+ z/ B, sand CustomerID = 20$ u% c7 K' ?) d6 a
and (StatusID  2 and StatusID  7)
7 f; Y$ p0 J" g5 x5 cand SubcategoryID = 88; X% U8 A8 W$ l* C' T# v& Q0 e$ U
select Phone, ZipCode, sum(Calls) as Calls, sum(Sales) as Sales6 L2 U/ s2 D. E6 m2 @
from Archive 3 P+ P. R2 J4 M( M! B( g+ f2 Z
where CustomerID = 20
8 S7 k0 w) L# t3 Q+ ~and ReportDate = '2/3/2011'
+ b1 C7 _2 }% e) v3 h! {8 b/ iand Phone in (
: d( F9 d7 N% i. S( w+ A    select Phone
7 Z8 p3 |: N' F, q& |( U    from #tempTable
% U4 U4 u6 A4 Q  H+ X9 T+ }$ C)0 H; S  E3 i( f/ T
group by Phone, ZipCode3 y9 M" C, \8 _
在过去的几周中,我一直注意到,不仅此查询的速度很慢,而且任何在IN子句中使用(有点复杂)子查询的查询都会破坏性能。是什么原因呢?0 E9 D; E; v* ~. s- ]: R
这些查询中唯一可以使用的索引是两个表的CustomerID上的非聚集索引。我查看了慢查询和快速查询的执行计划,发现Archive表上的非聚集索引查找是迄今为止成本最高的百分比(80-90%)。但是,唯一的区别是慢查询中的这一步的CPU成本为7.1,而快查询中的这一步的CPU成本为1.7。
7 o9 {) Q3 v% q* \+ d               
/ X) R1 V4 m! q' M3 c- f0 Y解决方案:
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则