避免把判斷處理放入 WHERE 條件

2021-04-13 04:42:11 字數 4002 閱讀 9288

業務需求如下:有表a

,在查詢的時候,需要根據標誌確定是查詢大於某個值的記錄,還是小於某個值的記錄 if

@a = 0

select [trannumber] from a

where [trannumber] < 10000

else

if @a = 1

select [trannumber] from a

where [trannumber] > 10000

select

[trannumber] from a

where

(@a = 0 and [trannumber] < 10000)

or(@a = 1 and [trannumber] > 10000)

從語句的簡捷性來看,方法

b具有技巧性,它們兩者之間,究竟那乙個更好呢?你可能會從效能上來評估,以決定到底用那一種。單純從語句上來看,兩者的效率差別應該不會非常大,實際測試的結果會如我們想象嗎?繼續往下看

declare

@a int

set@a = 0

declare

@t table(

id int

identity,

a int

, b int)

declare

@dt datetime

, @loop int

, @id int

set@loop = 1

while

@loop < 10

begin

set @loop = @loop + 1

raiserror

('test %d'

, 10, 1, @loop)

with nowait

set @dt =

getdate()

if @a = 0

select

*from a

where [trannumber] < 10000

else

if @a = 1

select

*from a

where [trannumber] > 10000

insert @t(a)

values

(datediff

(ms, @dt,

getdate

()))

select @id =

scope_identity

(), @dt =

getdate()

select

*from a

where

(@a = 0 and [trannumber] < 10000) or

(@a = 1 and [trannumber] > 10000)

update @t set b =

datediff

(ms, @dt,

getdate

())

where id = @id

endselect

*from @t

union

all

select

null,

sum(a),

sum(b)

from @t

id          a           b

----------- ----------- -----------

1           173         173

2           140         170

3           140         173

4           126         170

5           140         173

6           140         173

7           123         170

8           190         170

9           123         190

null        1295        1562

除了效能外,另乙個要考慮的問題是block的問題,下面的測試來反映block的影響

-- run query windows 1

begin

tran

update a set [item] =

right(

newid

(), 4)

where [trannumber] < 100

--rollback tran

-- run query windows 2

declare

@a int

set@a = 1

if@a = 0

select

*from a

where [trannumber] < 10000

else

if @a = 1

select

*from a

where [trannumber] > 10000

-- run query windows 3

declare

@a int

set@a = 1

select

*from a

where

(@a = 0 and [trannumber] < 10000)

or

(@a = 1 and [trannumber] > 10000)

結果

你會看到,查詢視窗

b中的查詢會及時地完成,而查詢視窗

c的查詢會一直等待,你可以通過執行儲存過程

sp_who2

,檢視當前的

block

狀況來確定查詢視窗

c的查詢是否被查詢視窗

a的查詢

block住

usetempdb go

setnocount

on--***********************************=== --

建立測試環境

--***********************************===

raiserror('

建立測試環境',

10, 1)

with nowait

-- table a

create

table [dbo].a(

[trannumber] [int] identity

(1, 1)

notnull,

[invno] [char](8)

notnull,

[item] [char](15)

null

default(''

),primary

key([trannumber]))

create

index [indexoninvno] on [dbo].a([invno])

create

index [indexonitem] on [dbo].a ([item])

create

index [indexoniteminnvo] on [dbo].a([invno], [item])go

--***********************************=== --

生成測試資料

--***********************************===

raiserror('

生成測試資料',

10, 1)

with nowait

insert

[dbo].a([invno], [item])

select

left(

newid

(), 8),

right(

newid

(), 15)

from

syscolumns a, syscolumns b

避免把判斷處理放入 WHERE 條件

問題描述 業務需求如下 有表a,在查詢的時候,需要根據標誌確定是查詢大於某個值的記錄,還是小於某個值的記錄 a 一般的處理方法 if a 0 select trannumber from a where trannumber 10000 else if a 1 select trannumber f...

避免把判斷處理放入 WHERE 條件

問題描述 業務需求如下 有表a,在查詢的時候,需要根據標誌確定是查詢大於某個值的記錄,還是小於某個值的記錄 a 一般的處理方法 if a 0 select trannumber from a where trannumber 10000 else if a 1 select trannumber f...

把SQL Server放入保險箱

安全模式簡介 從系統結構上來講sql server有兩種安全模式。第一種是 僅windows 模式,這種模式只允許擁有受信任的windows nt賬戶的使用者登入,是sql server預設的安全模式,也是較安全的選項,使用者登入sql server的前提是該使用者使用windows nt的域賬戶登...