目錄
1、巢狀迴圈聯接
2、合併聯接
3、雜湊聯接
聯接(join)是將兩個表合併為乙個表的操作。sol的聯接分為外聯接、內聯接和交叉聯接。本文將主要通過查詢執行計畫的角度從本質上講解聯接。
巢狀迴圈聯接(nested loop join)也稱為「巢狀選代」,它將乙個聯接輸入用作外部輸入表(顯示為圖形執行計畫中的頂端輸入),將另乙個聯接輸入用作內部(底端)輸入表。外部迴圈逐行處理外部輸入表。內部迴圈會針對每個外部行執行,在內部輸入表中搜尋匹配行。
最簡單的情況是,搜尋時掃瞄整個表或索引,這稱為「單純巢狀迴圈聯接」。如果搜尋時使用索引,則稱為「索引巢狀迴圈聯接」。如果將索引生成為查詢計畫的一部分(並在查詢完成後立即將索引破壞),則稱為「臨時索引套迴圈聯接」。查詢優化器考慮了所有這些不同的情況。
如果外部輸入較小而內部輸入較大,且預先建立了案引,則使用巢狀迴圈聯接尤其有效,在許多小事務中(如那些只影響較小的一組行的事務),索引巢狀迴圈聯接優於合併聯接和雜湊聯接。但在大型查詢中,巢狀迴圈聯接通常不是最佳選擇。
在程式中可以理解為巢狀的for迴圈語句,先是對外部輸入表迴圈找到每行資料,再使用迴圈對內部輸入表的每行資料與外部輸入表的資料進行匹配,直到這2個迴圈都完成。例如建立班級表和學生表,然後對這兩個表進行內聯接,則系統將採用巢狀迴圈聯接對這兩個表進行處理。如下:
if object_id('class') is not null
drop table class;
gocreate table class
( cid int not null primary key,
cname varchar(10) not null
);go
if object_id('student') is not null
drop table student;
gocreate table student
( sid int identity primary key,
cid int not null,
sname varchar(10) not null,
constraint fk_student_class foreign key(cid) references class(cid)
);go
--插入測試資料
insert into class values
(1,'01'),
(2,'02');
insert into student(cid,sname) values
(1,'s11'),
(1,'s12'),
(2,'s21'),
(2,'s22'),
(2,'s23');
內聯接查詢這2個表,同時返回查詢的執行計畫,查詢**如下:
--內聯接
select *
from student as s
inner join class as c
on s.cid = c.cid;
執行計畫:
合併聯接(merge join)要求兩個輸入都在合併列上排序,其由聯接謂詞的等效(on)子句定義。通常,利用查詢優化器掃瞄索引(如果在適當的一組列上存在索引),或在合併聯接的下面放乙個排序運算子。在極少數情況下,雖然可能有多個等效子句,但只用其中一些可用的等效子句獲得合併列。
由於每個輸入都已排序,因此 merge join運算子將從每個輸入獲取一行並將其進行比較。例如,對於內聯接操作( inner.jon),如果獲取的行相等則返回該行。如果行不相等,則拋棄值較小的行並從該輸入獲得另一行進行比較。這一過程將重複進行,直到處理完所有的行為止。
合併聯接操作可以是常規操作,也可以是多對多操作。多對多合併聯接使用臨時表儲存行。如果每個輸入中有重複值,則在處理其中乙個輸入中的每個重複項時,另乙個輸入必須重繞到重複項的開始位置。
如果存在駐留謂詞,則所有滿足合併謂詞的行都將對該駐留謂詞取值,而只返回那些滿足該駐留謂詞的行。
合併聯接本身的速度很快,但如果需要執行排序操作,選擇合併聯接就會非常費時。然而,如果資料量很大且能夠從現有b樹索引中獲得預排序的所需資料,則合併聯接通常是最快的可用聯接演算法。例如仍然使用前面建立的班級和學生表,由於合併聯接在兩表資料量並不小而且聯接列已排序的情況下發生,所以需要向表中新增大量資料,同時還要為進行聯接的列cid排序,具體sql**如下:
set nocount on
--建立大量的測試資料
declare @i int =3
while @i <1000
begin
insert into class values(@i,'01')
declare @j int =0
while @j<10
begin
insert into student(cid,sname) values
(@i,'s'+convert(varchar(5),@i))
set @j += 1
endset @i += 1
endgo
--建立索引
create index ix_student_cid
on student(cid) include(sid,sname);
接下來執行兩個表的聯接查詢(上面的查詢語句),可以看到執行計畫中使用了合併聯接:
雜湊聯接(hash join)有兩種輸入,即生成輸入和探測輸入。如果兩個聯接輸入都大,而且大小差不多,則預先排序的合併聯接提供的效能與雜湊聯接相近。但是,如果這兩個輸入的大小相差很大,則雜湊聯接操作通常快得多。
雜湊聯接先掃瞄或計算整個生成輸入,然後在記憶體中生成雜湊表。根據計算得出的希鍵的雜湊值,將每行插入雜湊儲存桶。如果整個生成輸入小於可用記憶體,則可以將所有行都插入雜湊表中。生成階段之後是探測階段。一次一行地對整個探測輸入進行掃瞄或計算,並為每個探測行計算雜湊鍵的值,掃瞄相應的雜湊儲存桶並生成匹配項。
雜湊聯接一般在一張小表和一張大表進行聯接時應用。例如對於班級表和學生表,明顯班級表要比學生錶小很多,在去掉學生表上對cid的排序後,這兩個表在進行聯接運算時將使用雜湊聯接。詳細**如下:
--刪除索引
drop index ix_student_cid on student;
go--執行查詢
select *
from student as s
inner join class as c
on s.cid = c.cid
執行計畫如下:
SQL聯接查詢
舉例有兩表資訊如下 以上兩種查詢方式等價,如下圖所示內聯接inner join只取兩表存在關聯關係的資料 注 inner join與join相同,inner可省略不寫。查詢結果如下 如下圖所示,左聯接 左外聯接 左表 user表 資料將會完全展示,右表 dept表 只展示與左表存在關聯關係的資料。注...
SQL聯接查詢
聯接查詢 join表操作符對兩個輸入表進行了操作。聯結有三種基本型別 交叉連線,內連線,外鏈結。這三種連線的區別是它們採用的邏輯查詢處理步驟各部相同,每種連線都有一套不同的步驟。交叉連線只有乙個步驟 笛卡爾積 內連線有兩個步驟 笛卡爾積,過濾 外鏈結有三個步驟 笛卡爾積,過濾,新增外部行。交叉連線 ...
sql 左聯接,右聯接,內聯接的比較
首先需要解釋一下這幾個聯接的意思 2 left join 左聯接 返回包括左表中的所有記錄和右表中聯結字段相等的記錄。3 right join 右聯接 返回包括右表中的所有記錄和左表中聯結字段相等的記錄。inner join 等值連線 只返回兩個表中聯結字段相等的行。接下來,建立乙個資料庫,然後建立...