sql語句的優化分析

開門見山,問題所在

sql語句性能達不到你的要求,執行效率讓你忍無可忍,通常會時下面幾種狀況。html

  • 網速不給力,不穩定。
  • 服務器內存不夠,或者SQL 被分配的內存不夠。
  • sql語句設計不合理
  • 沒有相應的索引,索引不合理
  • 沒有有效的索引視圖
  • 表數據過大沒有有效的分區設計
  • 數據庫設計太2,存在大量的數據冗餘
  • 索引列上缺乏相應的統計信息,或者統計信息過時
  • ....

那麼咱們如何給找出來致使性能慢的的緣由呢?sql

  • 首先你要知道是否跟sql語句有關,確保不是機器開不開機,服務器硬件配置太差,沒網你說p啊
  • 接着你使用我上一篇文章中提到的2柯南sql性能檢測工具--sql server profiler,分析出sql慢的相關語句,就是執行時間過長,佔用系統資源,cpu過多的
  • 而後是這篇文章要說的,sql優化方法跟技巧,避免一些不合理的sql語句,取暫優sql
  • 再而後判斷是否使用啦,合理的統計信息。sql server中能夠自動統計表中的數據分佈信息,定時根據數據狀況,更新統計信息,是頗有必要的
  • 確認表中使用啦合理的索引,這個索引我前面博客中也有提過,不過那篇博客以後,還要進一步對索引寫篇文章
  • 數據太多的表,要分區,縮小查找範圍

分析比較執行時間計劃讀取狀況

select * from dbo.Product

執行上面語句通常狀況下只給你返回結果和執行行數,那麼你怎麼分析呢,怎麼知道你優化以後跟沒有優化的區別呢。數據庫

下面給你說幾種方法。緩存

1.查看執行時間和cpu佔用時間服務器

set statistics time on
select * from dbo.Product
set statistics time off

打開你查詢以後的消息裏面就能看到啦。數據結構

2.查看查詢對I/0的操做狀況數據庫設計

set statistics io on
select * from dbo.Product
set statistics io off

執行以後工具

 

掃描計數:索引或表掃描次數性能

邏輯讀取:數據緩存中讀取的頁數優化

物理讀取:從磁盤中讀取的頁數

預讀:查詢過程當中,從磁盤放入緩存的頁數

lob邏輯讀取:從數據緩存中讀取,image,text,ntext或大型數據的頁數

lob物理讀取:從磁盤中讀取,image,text,ntext或大型數據的頁數

lob預讀:查詢過程當中,從磁盤放入緩存的image,text,ntext或大型數據的頁數

 

若是物理讀取次數和預讀次說比較多,可使用索引進行優化。

若是你不想使用sql語句命令來查看這些內容,方法也是有的,哥教你更簡單的。

查詢--->>查詢選項--->>高級

被紅圈套上的2個選上,去掉sql語句中的set statistics io/time on/off 試試效果。哦也,你成功啦。。

3.查看執行計劃,執行計劃詳解

選中查詢語句,點擊而後看消息裏面,會出現下面的圖例

首先我這個例子的語句太過簡單,你整個複雜的,包涵啊。

分析鼠標放在圖標上會顯示此步驟執行的詳細內容,每一個表下面都顯示一個開銷百分比,分析站百分比多的的一塊,能夠根據從新設計數據結構,或這重寫sql語句,來對此進行優化。若是存在掃描表,或者掃描彙集索引,這表示在當前查詢中你的索引是不合適的,是沒有起到做用的,那麼你就要修改完善優化你的索引,具體怎麼作,你能夠根據我上一篇文章中的sql優化利器--數據庫引擎優化顧問對索引進行分析優化。

select查詢藝術

1.保證不查詢多餘的列與行。

  • 儘可能避免select * 的存在,使用具體的列代替*,避免多餘的列
  • 使用where限定具體要查詢的數據,避免多餘的行
  • 使用top,distinct關鍵字減小多餘重複的行

2.慎用distinct關鍵字

distinct在查詢一個字段或者不多字段的狀況下使用,會避免重複數據的出現,給查詢帶來優化效果。

可是查詢字段不少的狀況下使用,則會大大下降查詢效率。

由這個圖,分析下:

很明顯帶distinct的語句cpu時間和佔用時間都高於不帶distinct的語句。緣由是當查詢不少字段時,若是使用distinct,數據庫引擎就會對數據進行比較,過濾掉重複數據,然而這個比較,過濾的過程則會絕不客氣的佔用系統資源,cpu時間。

3.慎用union關鍵字

此關鍵字主要功能是把各個查詢語句的結果集合併到一個結果集中返回給你。用法

<select 語句1>
union
<select 語句2>
union
<select 語句3>
...

知足union的語句必須知足:1.列數相同。 2.對應列數的數據類型要保持兼容。

執行過程:

依次執行select語句-->>合併結果集--->>對結果集進行排序,過濾重複記錄。

select * from 
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)  where p.id<10000
union
select * from 
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)  where p.id<20000 and p.id>=10000
union
select * from 
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum)  where p.id>20000   ---這裏能夠寫p.id>100 結果同樣,由於他篩選過啦

----------------------------------對比上下兩個語句-----------------------------------------
select * from 
(( orde o  left join orderproduct op on o.orderNum=op.orderNum )
inner join product p on op.proNum=p.productnum) 

 

因而可知效率確實低,因此不是在必要狀況下避免使用。其實有他執行的第三部:對結果集進行排序,過濾重複記錄。就能看出不是什麼好鳥。然而不對結果集排序過濾,顯然效率是比union高的,那麼不排序過濾的關鍵字有嗎?答,有,他是union all,使用union all能對union進行必定的優化。。

4.判斷表中是否存在數據

select count(*) from product 
select top(1) id from product

很顯然下面完勝

5.鏈接查詢的優化

首先你要弄明白你想要的數據是什麼樣子的,而後再作出決定使用哪種鏈接,這很重要。

各類鏈接的取值大小爲:

  • 內鏈接結果集大小取決於左右表知足條件的數量
  • 左鏈接取決與左表大小,右相反。
  • 徹底鏈接和交叉鏈接取決與左右兩個表的數據總數量
select * from 
( (select * from orde where OrderId>10000) o  left join orderproduct op on o.orderNum=op.orderNum )

select * from 
( orde o left join orderproduct op on o.orderNum=op.orderNum )
 where o.OrderId>10000

 

因而可知減小鏈接表的數據數量能夠提升效率。

insert插入優化

--建立臨時表
create table #tb1
(
 id int,
 name nvarchar(30),
 createTime datetime
)
declare @i int
declare @sql varchar(1000)
set @i=0
while (@i<100000)  --循環插入10w條數據
begin
  set @i=@i+1
  set @sql=' insert into #tb1 values('+convert(varchar(10),@i)+',''erzi'+convert(nvarchar(30),@i)+''','''+convert(nvarchar(30),getdate())+''')'
  exec(@sql)
end

我這裏運行時間是51秒

--建立臨時表
create table #tb2
(
 id int,
 name nvarchar(30),
 createTime datetime
)

declare @i int
declare @sql varchar(8000)
declare @j int
set @i=0
while (@i<10000)  --循環插入10w條數據
begin 
 set @j=0
 set @sql=' insert into #tb2 select '+convert(varchar(10),@i*100+@j)+',''erzi'+convert(nvarchar(30),@i*100+@j)+''','''+convert(varchar(50),getdate())+''''
 set @i=@i+1
 while(@j<10)
 begin   
   set @sql=@sql+' union all select '+convert(varchar(10),@i*100+@j)+',''erzi'+convert(nvarchar(30),@i*100+@j)+''','''+convert(varchar(50),getdate())+''''
   set @j=@j+1
 end 
 exec(@sql)
end

drop table #tb2
select count(1) from #tb2

我這裏運行時間大概是20秒

分析說明:insert into select批量插入,明顯提高效率。因此之後儘可能避免一個個循環插入。

優化修改刪除語句

若是你同時修改或刪除過多數據,會形成cpu利用率太高從而影響別人對數據庫的訪問。

若是你刪除或修改過多數據,採用單一循環操做,那麼會是效率很低,也就是操做時間過程會很漫長。

這樣你該怎麼作呢?

折中的辦法就是,分批操做數據。

delete product where id<1000
delete product where id>=1000 and id<2000
delete product where id>=2000 and id<3000
.....

固然這樣的優化方式不必定是最優的選擇,其實這三種方式都是能夠的,這要根據你係統的訪問熱度來定奪,關鍵你要明白什麼樣的語句是什麼樣的效果。

 

 

總結:優化,最重要的是在於你平時設計語句,數據庫的習慣,方式。若是你平時不在乎,彙總到一塊再作優化,你就須要耐心的分析,然而分析的過程就看你的悟性,需求,知識水平啦。

相關文章
相關標籤/搜索