SQLServer 優(yōu)化SQL語(yǔ)句 in 和not in的替代方案
更新時(shí)間:2010年04月30日 16:52:04 作者:
用IN寫(xiě)出來(lái)的SQL的優(yōu)點(diǎn)是比較容易寫(xiě)及清晰易懂,這比較適合現(xiàn)代軟件開(kāi)發(fā)的風(fēng)格。
但是用IN的SQL性能總是比較低的,從SQL執(zhí)行的步驟來(lái)分析用IN的SQL與不用IN的SQL有以下區(qū)別:
SQL試圖將其轉(zhuǎn)換成多個(gè)表的連接,如果轉(zhuǎn)換不成功則先執(zhí)行IN里面的子查詢(xún),再查詢(xún)外層的表記錄,如果轉(zhuǎn)換成功則直接采用多個(gè)表的連接方式查詢(xún)。由此可見(jiàn)用IN的SQL至少多了一個(gè)轉(zhuǎn)換的過(guò)程。一般的SQL都可以轉(zhuǎn)換成功,但對(duì)于含有分組統(tǒng)計(jì)等方面的SQL就不能轉(zhuǎn)換了。 推薦在業(yè)務(wù)密集的SQL當(dāng)中盡量不采用IN操作符
NOT IN 此操作是強(qiáng)列推薦不使用的,因?yàn)樗荒軕?yīng)用表的索引。推薦用NOT EXISTS 或(外連接+判斷為空)方案代替
在數(shù)據(jù)庫(kù)中有兩個(gè)表,一個(gè)是當(dāng)前表Info(id,PName,remark,impdate,upstate),一個(gè)是備份數(shù)據(jù)表bakInfo(id,PName,remark,impdate,upstate),將當(dāng)前表數(shù)據(jù)備份到備份表去,就涉及到not in 和in 操作了:
首先,添加10萬(wàn)條測(cè)試數(shù)據(jù)
create procedure AddData
as
declare @id int
set @id=0
while(@id<100000)
begin
insert into dbo.Info(id,PName,remark,impdate,upstate)
values(@id,convert(varchar,@id)+'0','abc',getdate(),0)
set @id=@id+1
end
exec AddData
使用not in 和in操作:
SET STATISTICS TIME ON
GO
--備份數(shù)據(jù)
insert into bakInfo(id,PName,remark,impdate,upstate)
select id,PName,remark,impdate,upstate from dbo.Info
where id not in(select id from dbo.bakInfo)
GO
SET STATISTICS TIME OFF
此操作執(zhí)行時(shí)間:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 3 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 453 毫秒,占用時(shí)間 = 43045 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--更改當(dāng)前表狀態(tài)
update Info set upstate=1 where id in(select id from dbo.bakInfo)
此操作執(zhí)行時(shí)間:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 62 毫秒,占用時(shí)間 = 79 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 188 毫秒,占用時(shí)間 = 318 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--刪除當(dāng)前表數(shù)據(jù)
delete from Info where upstate=1 and id in(select id from dbo.bakInfo)
此操作執(zhí)行時(shí)間:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 183 毫秒,占用時(shí)間 = 183 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 187 毫秒,占用時(shí)間 = 1506 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
使用join連接替代方案:
SET STATISTICS TIME ON
GO
--備份數(shù)據(jù)
insert into bakInfo(id,PName,remark,impdate,upstate)
select id,PName,remark,impdate,upstate from
(SELECT Info.id,Info.PName, Info.remark, Info.impdate,Info.upstate, bakInfo.id AS bakID
FROM Info left JOIN
bakInfo ON Info.id = bakInfo.id ) as t
where t.bakID is null and t.upstate=0
GO
SET STATISTICS TIME OFF;
此操作執(zhí)行時(shí)間:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 247 毫秒,占用時(shí)間 = 247 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 406 毫秒,占用時(shí)間 = 475 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--更改當(dāng)前表狀態(tài)
update Info set upstate=1
FROM Info INNER JOIN
bakInfo ON Info.id = bakInfo.id
此操作執(zhí)行時(shí)間:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 4 毫秒,占用時(shí)間 = 4 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 219 毫秒,占用時(shí)間 = 259 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--刪除當(dāng)前表數(shù)據(jù)
delete from Info
FROM Info INNER JOIN
bakInfo ON Info.id = bakInfo.id
where Info.upstate=1
此操作執(zhí)行時(shí)間:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 177 毫秒,占用時(shí)間 = 177 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 219 毫秒,占用時(shí)間 = 550 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
可以看出使用join方案比使用not in 和in執(zhí)行時(shí)間要短很多了
SQL試圖將其轉(zhuǎn)換成多個(gè)表的連接,如果轉(zhuǎn)換不成功則先執(zhí)行IN里面的子查詢(xún),再查詢(xún)外層的表記錄,如果轉(zhuǎn)換成功則直接采用多個(gè)表的連接方式查詢(xún)。由此可見(jiàn)用IN的SQL至少多了一個(gè)轉(zhuǎn)換的過(guò)程。一般的SQL都可以轉(zhuǎn)換成功,但對(duì)于含有分組統(tǒng)計(jì)等方面的SQL就不能轉(zhuǎn)換了。 推薦在業(yè)務(wù)密集的SQL當(dāng)中盡量不采用IN操作符
NOT IN 此操作是強(qiáng)列推薦不使用的,因?yàn)樗荒軕?yīng)用表的索引。推薦用NOT EXISTS 或(外連接+判斷為空)方案代替
在數(shù)據(jù)庫(kù)中有兩個(gè)表,一個(gè)是當(dāng)前表Info(id,PName,remark,impdate,upstate),一個(gè)是備份數(shù)據(jù)表bakInfo(id,PName,remark,impdate,upstate),將當(dāng)前表數(shù)據(jù)備份到備份表去,就涉及到not in 和in 操作了:
首先,添加10萬(wàn)條測(cè)試數(shù)據(jù)
復(fù)制代碼 代碼如下:
create procedure AddData
as
declare @id int
set @id=0
while(@id<100000)
begin
insert into dbo.Info(id,PName,remark,impdate,upstate)
values(@id,convert(varchar,@id)+'0','abc',getdate(),0)
set @id=@id+1
end
exec AddData
使用not in 和in操作:
復(fù)制代碼 代碼如下:
SET STATISTICS TIME ON
GO
--備份數(shù)據(jù)
insert into bakInfo(id,PName,remark,impdate,upstate)
select id,PName,remark,impdate,upstate from dbo.Info
where id not in(select id from dbo.bakInfo)
GO
SET STATISTICS TIME OFF
此操作執(zhí)行時(shí)間:
復(fù)制代碼 代碼如下:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 3 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 453 毫秒,占用時(shí)間 = 43045 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--更改當(dāng)前表狀態(tài)
update Info set upstate=1 where id in(select id from dbo.bakInfo)
此操作執(zhí)行時(shí)間:
復(fù)制代碼 代碼如下:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 62 毫秒,占用時(shí)間 = 79 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 188 毫秒,占用時(shí)間 = 318 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--刪除當(dāng)前表數(shù)據(jù)
delete from Info where upstate=1 and id in(select id from dbo.bakInfo)
此操作執(zhí)行時(shí)間:
復(fù)制代碼 代碼如下:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 183 毫秒,占用時(shí)間 = 183 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 187 毫秒,占用時(shí)間 = 1506 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
使用join連接替代方案:
復(fù)制代碼 代碼如下:
SET STATISTICS TIME ON
GO
--備份數(shù)據(jù)
insert into bakInfo(id,PName,remark,impdate,upstate)
select id,PName,remark,impdate,upstate from
(SELECT Info.id,Info.PName, Info.remark, Info.impdate,Info.upstate, bakInfo.id AS bakID
FROM Info left JOIN
bakInfo ON Info.id = bakInfo.id ) as t
where t.bakID is null and t.upstate=0
GO
SET STATISTICS TIME OFF;
此操作執(zhí)行時(shí)間:
復(fù)制代碼 代碼如下:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 247 毫秒,占用時(shí)間 = 247 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 406 毫秒,占用時(shí)間 = 475 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--更改當(dāng)前表狀態(tài)
update Info set upstate=1
FROM Info INNER JOIN
bakInfo ON Info.id = bakInfo.id
此操作執(zhí)行時(shí)間:
復(fù)制代碼 代碼如下:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 4 毫秒,占用時(shí)間 = 4 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 219 毫秒,占用時(shí)間 = 259 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
--刪除當(dāng)前表數(shù)據(jù)
復(fù)制代碼 代碼如下:
delete from Info
FROM Info INNER JOIN
bakInfo ON Info.id = bakInfo.id
where Info.upstate=1
此操作執(zhí)行時(shí)間:
復(fù)制代碼 代碼如下:
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 177 毫秒,占用時(shí)間 = 177 毫秒。
SQL Server 執(zhí)行時(shí)間:
CPU 時(shí)間 = 219 毫秒,占用時(shí)間 = 550 毫秒。
(100000 行受影響)
SQL Server 分析和編譯時(shí)間:
CPU 時(shí)間 = 0 毫秒,占用時(shí)間 = 1 毫秒。
可以看出使用join方案比使用not in 和in執(zhí)行時(shí)間要短很多了
您可能感興趣的文章:
- 淺談MySQL中優(yōu)化sql語(yǔ)句查詢(xún)常用的30種方法
- sql語(yǔ)句優(yōu)化之用EXISTS替代IN、用NOT EXISTS替代NOT IN的語(yǔ)句
- SQL SERVER 的SQL語(yǔ)句優(yōu)化方式小結(jié)
- MySQL SQL語(yǔ)句優(yōu)化的10條建議
- Mysql查詢(xún)最近一條記錄的sql語(yǔ)句(優(yōu)化篇)
- SQL Server中的SQL語(yǔ)句優(yōu)化與效率問(wèn)題
- 常用SQL語(yǔ)句優(yōu)化技巧總結(jié)【經(jīng)典】
- SQL語(yǔ)句優(yōu)化方法30例(推薦)
- 如何優(yōu)化SQL語(yǔ)句的心得淺談
- 你真的知道怎么優(yōu)化SQL嗎
相關(guān)文章
sql server實(shí)現(xiàn)在多個(gè)數(shù)據(jù)庫(kù)間快速查詢(xún)某個(gè)表信息的方法
這篇文章主要介紹了sql server實(shí)現(xiàn)在多個(gè)數(shù)據(jù)庫(kù)間快速查詢(xún)某個(gè)表信息的方法,結(jié)合實(shí)例形式分析了SQL Server多個(gè)數(shù)據(jù)庫(kù)查詢(xún)的相關(guān)操作技巧,代碼備有詳盡的注釋,需要的朋友可以參考下2017-03-03SQL Server實(shí)現(xiàn)分頁(yè)方法介紹
這篇文章介紹了SQL Server實(shí)現(xiàn)分頁(yè)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03SQL Server AlwaysOn讀寫(xiě)分離配置圖文教程
這篇文章主要介紹了SQL Server AlwaysOn讀寫(xiě)分離配置圖文教程,需要的朋友可以參考下2017-09-09sqlserver禁止management studio的自動(dòng)提交事務(wù)
默認(rèn)management studio是自動(dòng)提交事務(wù),即一個(gè)語(yǔ)句就一個(gè)事務(wù),那么如何禁止其自動(dòng)提交呢?下面有個(gè)不錯(cuò)的方法,大家可以參考下2014-06-06SQLSERVER 的 truncate 和 delete 區(qū)別解析
在面試中我相信有很多朋友會(huì)被問(wèn)到 truncate 和 delete 有什么區(qū)別,接下來(lái)通過(guò)本文給大家普及下SQLSERVER 的 truncate 和 delete 有區(qū)別,需要的朋友可以參考下2023-02-02將Sql Server對(duì)象的當(dāng)前擁有者更改成目標(biāo)擁有者
將Sql Server對(duì)象的當(dāng)前擁有者更改成目標(biāo)擁有者...2006-10-10詳解SQL Server表和索引存儲(chǔ)結(jié)構(gòu)
這篇文章主要介紹了詳解SQL Server表和索引存儲(chǔ)結(jié)構(gòu),有助于大家對(duì)SQL存儲(chǔ)方式有深入的理解,參考學(xué)習(xí)下吧。2017-11-11