SQL Server SQL性能優化之--pivot行列轉換減少掃描計數優化查詢語句


原文出處:http://www.cnblogs.com/wy123/p/5933734.html

 

 

先看常用的一種表結構設計方式:

 

那么可能會遇到一種典型的查詢方式,主子表關聯,查詢子表中的某些(或者全部)Key點對應的Value,橫向顯示(也即以行的方式顯示)

 

這種查詢方式很明顯的一個卻顯示多次對字表查詢(暫時拋開索引)

 

相比這種查詢方式很多人都遇到過,如果子表是配置信息之類的小表的話,問題不大,如果字表數據量較大,可能就會有影響了。

這個查詢目的是將”縱表”存儲的結果“橫向”顯示,相當於橫列轉換的感覺了。
可以將子表的結果一次性將縱表的結果轉換成橫標,再跟主表連接,
然后得到一個最終一樣的查詢結果(格式),就能夠減少子表的查詢次數
這里將子表的結果“一次性將縱表的結果轉換成橫標”,是典型的行列轉換操作

 

首先先看一下這里所說的一次轉換成橫標的這一步驟,需要借助pivot,一步一步來

 

然后看跟主表join之后,兩種查詢方式的整體查詢結果

 

那么看一下后一種查詢方式也即通過行業轉換之后做join的執行計划,可以看到只對字表進行了一次查找(這里是index seek,但是暫拋開索引)

 

觀察一下兩條SQL的IO信息,可以發現,前者的Scan count是5,邏輯讀是65,后者的Scan count是1,邏輯讀是13,65=13*5。可見后者是一次性將表中的幾個Key值讀取出來的,而前者每個Key值讀取一次表。

 

總結:

  改寫SQL是實現優化的思路之一,當然改寫SQL技巧有很多種,本文僅對某一類典型查詢提供一個改寫思路,避免對一個表進行多次讀取的方式來實現的查詢。
  通過改寫一個常用的查詢寫法,從而實現一個等價的邏輯來減少對基表的讀取次數來達到SQL優化的目的。
  當然實際情況可能更加復雜,采用該思路改寫的時候要注意針對SQL語句測試驗證。

附上本文的測試腳本

create table HeaderTable
(
    HeaderId int ,
    OtherColumn varchar(50)
)


create table DetailTable
(
    HeaderId int,
    DetailId int identity(1,1),
    DetailKey varchar(50),
    DetailValues int
)


declare @i int = 0
while @i<1000000
begin
    insert into HeaderTable values (@i,NEWID())
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0001',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0002',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0003',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0004',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0005',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0006',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0007',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0008',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0009',RAND()*10000)
    insert into DetailTable (HeaderId,DetailKey,DetailValues)values(@i,'A0010',RAND()*10000)
    set @i=@i+1
end

create index idx_HeaderId on HeaderTable(HeaderId)

create index idx_HeaderId on DetailTable(HeaderId)

create index idx_DetailKey on DetailTable(DetailKey)



select *,
(select DetailValues from DetailTable t where t.HeaderId = a.HeaderId and  t.DetailKey = 'A0001') as 'Key1的值',
(select DetailValues from DetailTable t where t.HeaderId = a.HeaderId and  t.DetailKey = 'A0002') as 'Key2的值',
(select DetailValues from DetailTable t where t.HeaderId = a.HeaderId and  t.DetailKey = 'A0003') as 'Key3的值',
(select DetailValues from DetailTable t where t.HeaderId = a.HeaderId and  t.DetailKey = 'A0004') as 'Key4的值',
(select DetailValues from DetailTable t where t.HeaderId = a.HeaderId and  t.DetailKey = 'A0005') as 'Key5的值'
from HeaderTable a 
where a.HeaderId = 10000


SELECT 
a.*,
t.A0001 as  'Key1的值',
t.A0002 as  'Key2的值',
t.A0003 as  'Key3的值',
t.A0004 as  'Key4的值',
t.A0005 as  'Key5的值'
from HeaderTable a inner join
(select HeaderId ,DetailKey ,DetailValues from DetailTable)t
 pivot( MAX(DetailValues) FOR DetailKey IN (A0001,A0002,A0003,A0004,A0005)
)t  on t.HeaderId = a.HeaderId
where a.HeaderId = 10000

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM