SqlServer中的UNION操作符在合并資料時去重的原理以及UNION運算子查詢結果預設排序的問題

來源:互聯網
上載者:User

標籤:end   好的   hellip   開場白   created   date   這一   純粹   ble   

原文:SqlServer中的UNION操作符在合并資料時去重的原理以及UNION運算子查詢結果預設排序的問題

 

本文出處:http://www.cnblogs.com/wy123/p/7884986.html 

 

 

周圍又有人在討論UNION和UNION ALL,對於UNION和UNION ALL,網上說的最多的就是效能問題(實在不想說出來這句話:UNION ALL比UNION快)
其實根本不想炒UNION和UNION ALL這碗剩飯了,
每次看到網上說用這個不用那個,列舉的一條一條的那種文章,只要看到說UNION ALL比UNION效能好的就……

對於合并的結果集,UNION是去重的,UNION ALL是不去重的,去重與不去重是兩個目的,分別由UNION和UNION ALL實現
兩個作用(功能)不同的東西,放一起比效能有什麼意義?
這種問題真的是無聊至極,就好比“足球場上的某個中後衛和某個前腰哪個能力更強”一樣沒有可比性,
他們的作用本身就是不同的,難道說中後衛能力不行,把他撤下來,用一個牛逼的前腰球員替代中後衛,或者是前腰能力不行,撤下他用牛逼的中後衛替代?
這是在功能上的區別,至於效能,我個人認為對比起來沒有任何意義。
如果非要放一起比的話,做同樣的資料合併,
UNION因為要去重,相對UNION ALL來說,(相對)當然會耗費更多的資源(耗費的資源多少跟效能無關,做的事情多,當然需要更多的資源)
但是一定要弄清楚,合并資料的時候,到底要不要去掉重複資料,這是最終結果對與錯的問題,不是效能問題!

這裡不討論UNION和UNION ALL的效能了,
從另外一個點入手來發起問題
UNION與UNION ALL最大的區別就是UNION會去重,那麼問題就來了,這個去重是怎麼實現的?去重會對查詢的預設順序集產生什麼影響?

 

UNION去重的實現

測試一下UNION運算子去重的實現原理

create table TestUnion1(            Id1 INT PRIMARY KEY,    Id2 tinyint,    Name varchar(100));create table TestUnion2(    Id1 INT PRIMARY KEY,    Id2 tinyint,    Name varchar(100));insert into TestUnion1 values (500,9,‘aaa‘)insert into TestUnion1 values (700,3,‘ccc‘)insert into TestUnion1 values (200,7,‘eee‘)insert into TestUnion2 values (300,2,‘bbb‘)insert into TestUnion2 values (800,8,‘ddd‘)insert into TestUnion2 values (100,5,‘fff‘)--TestUnionALL1和TestUnionALL2中相同的資料insert into TestUnion1 values (600,6,‘xxx‘)insert into TestUnion2 values (600,6,‘xxx‘)

UNION在去重的過程中,使用的執行計畫是Merge Join,UNION ALL是不去重的,同樣步驟對應的執行計畫是Concatenation

這裡UNION的去重動作是通過merge實現,這裡的merge join並不是表與表之間的merge join
這裡可以看出來,UNION產生的merge與 inner join產生的Merge的作用是有差異的

對於UNION的去重的這一動作,去當然不是說只有merge join一種,這裡只不過是兩個結果的資料都剛好有序才採用merge join來去重罷了

如果查詢欄位的順序的第一個欄位是叢集索引(或者主鍵),,正如上文提到的,UNION的雙方就會以merge的方式區中
如果查詢欄位的順序非叢集索引,UNION的過程是現將兩個結果集合并起來(上文提到的Concatenation),然後再做sort排序去重

  


UNION之後結果集的最終排序結果

UNION之後結果集的最終排序結果跟查詢欄位的順序有關,
如果查詢欄位的順序的第一個欄位是叢集索引(或者主鍵),正如上文提到的,UNION的雙方就會以merge的方式區中
如果查詢欄位的順序的第一個欄位是非叢集索引欄位,UNION的過程是現將兩個結果集合并起來(上文提到的Concatenation),然後再做sort排序去重
如下的執行個體能說說明這個問題,當查詢欄位的順序發生變化之後,兩者的執行計畫完全不一致。

或者再看一個case,當Name在最前面的時候,最終的結果就是按照name排序。

   可能有人會懷疑是不是資料量太小了,是不是巧合,這裡可以加大測試資料庫,在查詢條件中,讓非叢集索引參與到運算之中

create table TestUnion1(            Id1 INT PRIMARY KEY,    Id2 tinyint,    Name varchar(100),    CreateDate datetime);create table TestUnion2(    Id1 INT PRIMARY KEY,    Id2 tinyint,    Name varchar(100),    CreateDate datetime);begin tran    declare @i int = 0    while @i<1000000    begin        insert into TestUnion1 values (@i,rand()*200,newid(),getdate()-rand()*1000)        insert into TestUnion2 values (@i,rand()*200,newid(),getdate()-rand()*1000)        set @i=@i+1    endcommitcreate index idx_CreateDate on TestUnion1(CreateDate)create index idx_CreateDate on TestUnion2(CreateDate)

參考,一旦查詢結果集不是按照查詢欄位叢集索引排序的話,
比如這裡走的是createDate時間欄位的索引,執行計畫都是先按照普通的方式合并結果集,也即Concatenation
然後在利用Sort(Distinct)的方式排序去重,對於去重的結果的最終的排序,跟查詢結果的第一個欄位有關,且結果總是按照查詢的第一個欄位排序的。

  換一種查詢欄位的順序方式,看一下結果,仍舊是按照查序列的第一個欄位排序的

  UNION運算子在去重的時候,
  如果查詢欄位的第一個欄位是叢集索引,那麼會用merge join的方式合并+去重。
  如果查詢欄位的第一個欄位不是非叢集索引,那麼首先會將兩個(或者多個)結果集進行普通的合并,最後通過Sort Distinct的方式去重。  
  且UNION運算之後的預設排序方式,受查詢欄位前後的方式影響。 

 

總結:

  UNION和UNION ALL的作用是不一樣的,放在一起比效能沒有任何意義,真不想趟這趟渾水。
  合并結果集,需要去重就用UNION,不需要去重就用UNION ALL,如果兩個結果集中沒有重複的結果集,就用UNION ALL,
  這純粹是需求驅動的,而不是UNION和UNION ALL的效能問題。

 

多撤一句:
曾經大晚上接到一個面試電話,沒有任何開場白,第一句話是“我們電話面試一下可以嗎”,答曰可以,第二句話就是“UNION和UNION ALL的區別是什麼,有沒有效能差異”。
真的不希望再去對UNION和UNION ALL的效能上做討論。

SqlServer中的UNION操作符在合并資料時去重的原理以及UNION運算子查詢結果預設排序的問題

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.