問題描述
業務需求如下:
有表a,在查詢的時候,需要根據標誌確定是查詢大於某個值的記錄,還是小於某個值的記錄
a、一般的處理方法
if@a = 0
select [trannumber] from a
where [trannumber] < 10000
else
if @a = 1
select [trannumber] from a
where [trannumber] > 10000
b、一句的處理方法
select
[trannumber] from a
where
(@a = 0 and [trannumber] < 10000)
or(@a = 1 and [trannumber] > 10000)
分析
從語句的簡捷性來看,方法b具有技巧性,它們兩者之間,究竟那乙個更好呢?你可能會從效能上來評估,以決定到底用那一種。單純從語句上來看,兩者的效率差別應該不會非常大,實際測試的結果會如我們想象嗎?繼續往下看
建立測試環境(注,此測試環境是為幾個主題服務的,因此結構看起來有些怪異)
usetempdb go
setnocounton
--***********************************===
--建立測試環境
--***********************************===
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 go
進行效能測試
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
allselect
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的影響
block的測試—為表a加鎖(查詢視窗a)
-- run query windows 1
begin
tran
update a set [item] =
right(
newid
(), 4)
where [trannumber] < 100
--rollback tran
block的測試—測試查詢方法a(查詢視窗b)
-- 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
block的測試—測試查詢方法b(查詢視窗c)
-- 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住
結論
不要使用查詢方法b,它看起來很棒,實際的結果是效能不太好,而且會增加被block的機會
避免把判斷處理放入 WHERE 條件
業務需求如下 有表a 在查詢的時候,需要根據標誌確定是查詢大於某個值的記錄,還是小於某個值的記錄 if a 0 select trannumber from a where trannumber 10000 else if a 1 select trannumber from a where tra...
避免把判斷處理放入 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的域賬戶登...