日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

SQLSERVER中的假脱机spool

發(fā)布時(shí)間:2023/12/19 综合教程 29 生活家
生活随笔 收集整理的這篇文章主要介紹了 SQLSERVER中的假脱机spool 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

SQLSERVER中的假脫機(jī)spool

我發(fā)現(xiàn)網(wǎng)上對(duì)于假脫機(jī)的解釋都非常零散,究竟假脫機(jī)是什么?

這幾天在家里研究了一下,收集了很多網(wǎng)上的資料

假脫機(jī)是中文的翻譯,而英文的名字叫做spool

在徐老師寫的《SQLSERVER企業(yè)級(jí)平臺(tái)管理實(shí)踐》里提到了一下假脫機(jī)

在SQLSERVER I/O問(wèn)題的那一節(jié)

在性能監(jiān)視器里,有一個(gè)計(jì)數(shù)器“worktables/sec” :

每秒創(chuàng)建的工作表數(shù)。例如,工作表可用于存儲(chǔ)查詢假脫機(jī)(query spool),LOB變量,XML變量,表變量,游標(biāo)的臨時(shí)結(jié)果

在《剖析SQLServer執(zhí)行計(jì)劃》里也提到了假脫機(jī)

(13) 有時(shí)查詢優(yōu)化器需要在tempdb數(shù)據(jù)庫(kù)中建立臨時(shí)工作表。如果是這樣的話

就意味著圖形執(zhí)行計(jì)劃中有標(biāo)識(shí)成Index Spool, Row Count Spool或者Table Spool的圖標(biāo)。

任何時(shí)候,使用到工作表一般都會(huì)防礙到性能,因?yàn)樾枰~外的I/O開(kāi)銷來(lái)維護(hù)這個(gè)工作表。

之前本人也寫過(guò)一篇文章:對(duì)于索引假脫機(jī)的一點(diǎn)理解

寫這篇文章的時(shí)候當(dāng)時(shí)還是對(duì)假脫機(jī)一知半解

假脫機(jī)在MSDN中的執(zhí)行計(jì)劃中的邏輯運(yùn)算符和物理運(yùn)算符中提到了幾個(gè)假脫機(jī)相關(guān)的運(yùn)算符(詳見(jiàn)本文最后面)

Eager Spool

Lazy Spool

Index Spool (有時(shí)候也叫 Nonclustered Index Spool)

Row Count Spool

Spool

Table Spool

Window Spool

Spool, Table Spool, Index Spool, Window Spool 和 Row Count Spool是物理運(yùn)算符

Eager Spool 和 Lazy Spool是邏輯運(yùn)算符

這些運(yùn)算符描述了假脫機(jī)是如何工作的,在這里你需要非常清楚邏輯運(yùn)算符和物理運(yùn)算符的區(qū)別

MSDN中的解釋:

邏輯運(yùn)算符:邏輯運(yùn)算符描述了用于處理語(yǔ)句的關(guān)系代數(shù)操作。 換言之,邏輯運(yùn)算符從概念上描述了需要執(zhí)行哪些操作。

物理運(yùn)算符:物理運(yùn)算符實(shí)施由邏輯運(yùn)算符描述的操作。 每個(gè)物理運(yùn)算符都是一個(gè)執(zhí)行某項(xiàng)具體操作的對(duì)象或例程。

例如,某些物理運(yùn)算符可訪問(wèn)表、索引或視圖中的列或行。 其他物理運(yùn)算符執(zhí)行其他操作,如計(jì)算、聚合、數(shù)據(jù)完整性檢查或聯(lián)接。

物理運(yùn)算符具有與其關(guān)聯(lián)的開(kāi)銷。

注意:窗口假脫機(jī)是沒(méi)有Eager Spool和Lazy Spool之分的,因?yàn)樗仁沁壿嬤\(yùn)算符也是物理運(yùn)算符!!

簡(jiǎn)單來(lái)講SQLSERVER做某項(xiàng)操作由物理運(yùn)算符來(lái)做,而具體怎樣做就由邏輯運(yùn)算符來(lái)決定

打個(gè)比方:小明在佛山,想去廣州,小明可以選擇開(kāi)汽車去廣州,踩自行車去廣州,騎摩托車去廣州(相當(dāng)于做某項(xiàng)操作)

小明可以根據(jù)當(dāng)時(shí)的路況:

(1)踩自行車:如果道路比較擁堵,踩自行車不用怕,最多的車也能過(guò),他可以選擇使勁的踩(Eager Spool)或者慢慢踩(Lazy Spool)

(2)開(kāi)汽車:如果道路比較暢通,他可以選擇開(kāi)快一點(diǎn)(Eager Spool)或者開(kāi)慢一點(diǎn)(Lazy Spool)

(3)騎摩托車:如果道路比較擁堵,他可以選擇抄小路,然后開(kāi)快一點(diǎn)(Eager Spool)或者開(kāi)慢一點(diǎn)(Lazy Spool)

不知道這個(gè)比喻大家明白沒(méi)有,不過(guò)本人也找不到更好的比喻~

在圖形執(zhí)行計(jì)劃中,你會(huì)發(fā)現(xiàn)Table Spool 有時(shí)候會(huì)帶有 Eager Spool ,有時(shí)候有會(huì)帶有 Lazy Spool

因?yàn)門able Spool是物理運(yùn)算符,Eager Spool和Eager Spool 是邏輯運(yùn)算符


Table Spool(表假脫機(jī))

SQL腳本如下:

表假脫機(jī) Eager Spool

 1 ----表假脫機(jī) Eager Spool
 2 USE [Spool]
 3 GO
 4 CREATE TABLE Sales (EmpId INT, Yr INT, Sales MONEY)
 5 INSERT Sales VALUES(1, 2005, 12000)
 6 INSERT Sales VALUES(1, 2006, 18000)
 7 INSERT Sales VALUES(1, 2007, 25000)
 8 INSERT Sales VALUES(2, 2005, 15000)
 9 INSERT Sales VALUES(2, 2006, 6000)
10 INSERT Sales VALUES(3, 2006, 20000)
11 INSERT Sales VALUES(3, 2007, 24000)
12 
13 SELECT * FROM [dbo].[Sales]
14 
15 
16 SELECT EmpId, Yr, SUM(Sales) AS Sales
17 FROM Sales
18 GROUP BY EmpId, Yr WITH CUBE

View Code

例子出處:http://www.sqlskills.com/blogs/conor/grouping-sets-rollups-and-cubes-oh-my/

In this case, it writes the data to a temporary spool, sorts the output of that

and then re-reads that spool in the second branch.

表假脫機(jī) Lazy Spool

1 --表假脫機(jī) Lazy Spool
2 USE [AdventureWorks]
3 GO
4 SELECT *,COUNT(*) OVER()
5 from production.[Product] AS p
6 JOIN production.[ProductSubcategory] AS s
7 ON s.[ProductCategoryID]=p.[ProductSubcategoryID]

View Code

例子出處:http://sqlblog.com/blogs/rob_farley/archive/2013/06/11/spooling-in-sql-execution-plans.aspx


Row Count Spool(行計(jì)數(shù)假脫機(jī))

SQL腳本如下:

 1 --行計(jì)數(shù)假脫機(jī)
 2 USE [Spool]
 3 GO
 4 --建表
 5 CREATE TABLE tb1(ID int) 
 6 GO
 7 CREATE TABLE tb2(ID int) 
 8 GO
 9 
10 --插入測(cè)試數(shù)據(jù)
11 DECLARE @i INT 
12 SET @i= 500 
13 WHILE @i > 0 
14 begin 
15 INSERT INTO dbo.tb1 
16 VALUES ( @i 
17 ) 
18 SET @i = @i -1 
19 end 
20 GO
21 
22 DECLARE @i INT 
23 SET @i= 500 
24 WHILE @i > 0 
25 begin 
26 INSERT INTO dbo.tb2
27 VALUES ( @i 
28 ) 
29 SET @i = @i -1 
30 end 
31 
32 
33 --行計(jì)數(shù)假脫機(jī)
34 SELECT * FROM tb1 WHERE id NOT IN(SELECT id FROM tb2)

View Code

例子出處:http://niutuku.com/tech/MsSql/238716.shtml


Index Spool (索引假脫機(jī))

Lazy Spool

SQL腳本如下:

 1 --索引假脫機(jī)(Index Spool)
 2 USE [Spool]
 3 GO
 4 --建表
 5 create  table   tb(aa   int,bb   char(1)) 
 6 GO  
 7 
 8 --插入測(cè)試數(shù)據(jù)
 9 insert   tb   values(1,'A')   
10 insert   tb   values(1,'B')   
11 insert   tb   values(1,'C')   
12 insert   tb   values(1,'D')   
13 
14 insert   tb   values(2,'E')   
15 insert   tb   values(2,'F')   
16 insert   tb   values(2,'G')   
17 insert   tb   values(2,'H')   
18 
19 insert   tb   values(3,'I')   
20 insert   tb   values(3,'J')   
21 insert   tb   values(3,'K')   
22 insert   tb   values(3,'L')
23   
24 --查詢數(shù)據(jù)
25 SELECT  *
26 FROM    tb a
27 WHERE   bb = ( SELECT TOP 1
28                         bb
29                FROM     tb
30                WHERE    aa = a.aa
31                ORDER BY NEWID()
32              )

View Code

例子出處:http://www.cnblogs.com/lyhabc/archive/2013/04/19/3029840.html


Window Spool(窗口假脫機(jī))

Window Spool 這個(gè)執(zhí)行計(jì)劃和OVER() 開(kāi)窗函數(shù)息息相關(guān),因?yàn)橹挥蠴VER()函數(shù)才會(huì)使用到Window Spool 這個(gè)執(zhí)行計(jì)劃

http://msdn.microsoft.com/zh-cn/library/ms189461.aspx

大家可以看一下MSDN中對(duì)OVER()開(kāi)窗函數(shù)里ROWS選項(xiàng)RANGE選項(xiàng)的解釋

ROWS | RANGE
通過(guò)指定分區(qū)中的起點(diǎn)和終點(diǎn),進(jìn)一步限制分區(qū)中的行數(shù)。 這是通過(guò)按照邏輯關(guān)聯(lián)或物理關(guān)聯(lián)對(duì)當(dāng)前行指定某一范圍的行實(shí)現(xiàn)的。

物理關(guān)聯(lián)通過(guò)使用 ROWS 子句實(shí)現(xiàn)。

ROWS 子句通過(guò)指定當(dāng)前行之前或之后的固定數(shù)目的行,限制分區(qū)中的行數(shù)。

此外,RANGE 子句通過(guò)指定針對(duì)當(dāng)前行中的值的某一范圍的值,從邏輯上限制分區(qū)中的行數(shù)。

基于 ORDER BY 子句中的順序?qū)χ昂椭蟮男羞M(jìn)行定義。

窗口框架“RANGE … CURRENT ROW …”包括在 ORDER BY 表達(dá)式中與當(dāng)前行具有相同值的所有行。

例如,ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 意味著該函數(shù)對(duì)其操作的行的窗口在大小上是 3 行,以當(dāng)前行之前(包括當(dāng)前行)的 2 行開(kāi)頭。

SQL腳本如下:

 1 use master
 2 GO
 3 
 4 --range
 5 select count(*) over (order by id RANGE between current row and unbounded following)
 6 from   sysobjects
 7 order by id
 8 
 9 --rows
10 select count(*) over (order by type ROWS current row )
11 from   sysobjects
12 order by id

View Code

例子出處:http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=182542


對(duì)上面這些運(yùn)算符的解釋:

假脫機(jī)運(yùn)算符會(huì)取出表中的一部分的數(shù)據(jù)集,將他們存放在tempdb數(shù)據(jù)庫(kù)里的臨時(shí)結(jié)構(gòu)里

這個(gè)臨時(shí)結(jié)構(gòu)一般就是堆表或者非聚集索引,但是有一個(gè)物理運(yùn)算符例外,臨時(shí)結(jié)構(gòu)是不存放數(shù)據(jù)的,

他只存放假脫機(jī)里保存的數(shù)據(jù)的行數(shù),而這個(gè)物理運(yùn)算符就是Row Count spool

Index Spool:索引假脫機(jī)只有非聚集索引假脫機(jī),沒(méi)有聚集索引假脫機(jī),結(jié)合我以前寫的兩篇文章,解釋一下原因

SQLSERVER聚集索引與非聚集索引的再次研究(上)

SQLSERVER聚集索引與非聚集索引的再次研究(下)

SQLSERVER當(dāng)遇到復(fù)雜的查詢的時(shí)候,需要把部分結(jié)果集放到tempdb數(shù)據(jù)庫(kù)里的非聚集索引頁(yè)里(說(shuō)白了就是在tempdb數(shù)據(jù)庫(kù)里建立

表的非聚集索引)以加快查找的速度的時(shí)候就會(huì)用到索引假脫機(jī)

例如上面的例子,SQL語(yǔ)句用到了子查詢(tb表),SQLSERVER需要把子查詢里的結(jié)果集(tb表)進(jìn)行排序然后將結(jié)果集放進(jìn)去

非聚集索引里(對(duì)tb表建立非聚集索引),

然后用非聚集索引里的數(shù)據(jù)和主表(tb a)里的數(shù)據(jù)進(jìn)行聯(lián)接,并輸出結(jié)果

為什麼不用聚集索引?

SQLSERVER聚集索引與非聚集索引的再次研究(上/下)里說(shuō)到,非聚集索引和堆表是沒(méi)有連接在一起的,非聚集索引頁(yè)面只有指針

指向堆表的數(shù)據(jù)頁(yè),而聚集索引的葉子節(jié)點(diǎn)就是數(shù)據(jù)頁(yè),索引頁(yè)和數(shù)據(jù)頁(yè)連接在一起,如果建立聚集索引,就需要將表(tb表)中的數(shù)據(jù)

放入到tempdb數(shù)據(jù)庫(kù)里,這樣開(kāi)銷就會(huì)很大

或者用下面兩張圖來(lái)描述可能會(huì)清楚一點(diǎn),關(guān)鍵還是要讀懂 SQLSERVER聚集索引與非聚集索引的再次研究(上/下)

Table Spool:把表中的數(shù)據(jù)放進(jìn)tempdb數(shù)據(jù)庫(kù)里

為什麼第一個(gè)查詢會(huì)用到Table Spool?因?yàn)镃UBE這個(gè)數(shù)據(jù)匯總關(guān)鍵字會(huì)將表中的數(shù)據(jù)進(jìn)行匯總,匯總的過(guò)程比較復(fù)雜

把表中的數(shù)據(jù)放進(jìn)去tempdb數(shù)據(jù)庫(kù)里的工作表(worktable、臨時(shí)表、堆表)里進(jìn)行復(fù)雜的匯總計(jì)算是比較好的

他避免了阻塞,以防止長(zhǎng)期鎖住表中的數(shù)據(jù)

關(guān)于CUBE關(guān)鍵字可以看一下我這篇文章:SQLSERVER中的ALL、PERCENT、CUBE關(guān)鍵字、ROLLUP關(guān)鍵字和GROUPING函數(shù)

Row Count Spool:存放中間結(jié)果/表的數(shù)據(jù)的行數(shù),上面的例子里用于計(jì)算表中的數(shù)據(jù)行數(shù)并保存在tempdb數(shù)據(jù)庫(kù)的

Row Count Spool里,為后面兩表聯(lián)接選用執(zhí)行計(jì)劃提供選擇依據(jù)

Eager Spool邏輯運(yùn)算符:一次性將所有數(shù)據(jù)放入到Spool里

Lazy Spool邏輯運(yùn)算符:逐次逐次地將數(shù)據(jù)放入Spool里

在上面的例子里

Tabel Spool Eager Spool

SQLSERVER使用Eager Spool一次性將Sales 表中的數(shù)據(jù)存放到tempdb數(shù)據(jù)庫(kù)的工作表里面,方便快速統(tǒng)計(jì)

Row Count Spool

SQLSERVER使用計(jì)數(shù)器每次讀取到一行就加1,這樣一次一次地統(tǒng)計(jì)表中的行數(shù)(這里只是比喻,SQLSERVER內(nèi)部可能并不是這樣統(tǒng)計(jì)!)

Window Spools:根據(jù)MSDN中的定義,OVER 子句定義查詢結(jié)果集內(nèi)的窗口或用戶指定的行集。 然后,開(kāi)窗函數(shù)將計(jì)算窗口中每一行的值

SQLSERVER將窗口中的結(jié)果集放入Spool里,以加快后續(xù)操作的速度

對(duì)于單獨(dú)一個(gè)窗口來(lái)講:?jiǎn)为?dú)一個(gè)窗口屬于Eager Spool(一次性將結(jié)果集放進(jìn)去窗口里)

對(duì)于表中的窗口來(lái)講:屬于Lazy Spool ,因?yàn)槊總€(gè)窗口把數(shù)據(jù)存放進(jìn)去窗口里的速度/順序不是一致的,逐次逐次地將數(shù)據(jù)存放進(jìn)去每個(gè)窗口


為什麼需要假脫機(jī)?

主要有兩個(gè)原因:

1:數(shù)據(jù)需要再次被調(diào)用

2:使假脫機(jī)數(shù)據(jù)與源數(shù)據(jù)保持隔離

第二個(gè)原因很容易理解,就像第一個(gè)例子中的Tabel Spool那樣,需要把表數(shù)據(jù)放進(jìn)Tabel Spool里,以方便進(jìn)行數(shù)據(jù)匯總,

而不影響原表數(shù)據(jù)

第一個(gè)原因可以再舉一個(gè)例子

公用表表達(dá)式(CTE)

 1 USE [AdventureWorks]
 2 GO
 3 WITH managers AS(
 4 SELECT [EmployeeID],[ManagerID]
 5 from [HumanResources].[Employee]
 6 WHERE [ManagerID] IS NULL
 7 UNION ALL
 8 SELECT e.[EmployeeID],e.[ManagerID]
 9 from [managers] m
10 JOIN [HumanResources].[Employee] e
11 ON e.[ManagerID]=m.[EmployeeID]
12 )
13 
14 SELECT * FROM [managers]

索引假脫機(jī)運(yùn)算符負(fù)責(zé)把數(shù)據(jù)一條一條地塞進(jìn)去tempdb的非聚集索引里,并且是Lazy的,為什麼是Lazy的?

因?yàn)閯傞_(kāi)始的時(shí)候只有一行記錄,后來(lái)慢慢一條一條數(shù)據(jù)地從最右邊的表假脫機(jī)里獲取數(shù)據(jù)

我們還是先分析一下整個(gè)執(zhí)行計(jì)劃以方便理解,我們可以將整個(gè)執(zhí)行計(jì)劃拆解為三部分

第一部分執(zhí)行計(jì)劃的右上角

1 SELECT [EmployeeID],[ManagerID]
2 from [HumanResources].[Employee]
3 WHERE [ManagerID] IS NULL

這部分的執(zhí)行計(jì)劃只查找到一條記錄

他把這條記錄放入索引假脫機(jī)里

第二部分 UNION ALL

將第一部分的結(jié)果和第三部分的結(jié)果合并在一起

第三部分執(zhí)行計(jì)劃的右下角

1 SELECT e.[EmployeeID],e.[ManagerID]
2 from [managers] m
3 JOIN [HumanResources].[Employee] e
4 ON e.[ManagerID]=m.[EmployeeID]

最右邊的表假脫機(jī)運(yùn)算符負(fù)責(zé)把表數(shù)據(jù)裝載入表假脫機(jī)里,這個(gè)裝載過(guò)程也是逐條數(shù)據(jù)裝載的

那么,執(zhí)行計(jì)劃里的表假脫機(jī)和索引假脫機(jī)主要有什么用???

表假脫機(jī)主要用作公用表表達(dá)式里的遞歸調(diào)用

 1 WITH managers AS(
 2 SELECT [EmployeeID],[ManagerID]
 3 from [HumanResources].[Employee]
 4 WHERE [ManagerID] IS NULL
 5 UNION ALL
 6 SELECT e.[EmployeeID],e.[ManagerID]
 7 from [managers] m
 8 JOIN [HumanResources].[Employee] e
 9 ON e.[ManagerID]=m.[EmployeeID]
10 )

SELECT e.[EmployeeID],e.[ManagerID]
from [managers] m
JOIN [HumanResources].[Employee] e
ON e.[ManagerID]=m.[EmployeeID]

上面的代碼是每次遞歸的時(shí)候都需要調(diào)用到的,所以SQLSERVER干脆把表數(shù)據(jù)放到假脫機(jī)里的,不用每次都去查找記錄了

而索引假脫機(jī)是方便外部代碼調(diào)用公用表表達(dá)式的時(shí)候不用每次都去計(jì)算公用表表達(dá)式的結(jié)果,直接把公用表表達(dá)式的結(jié)果

放進(jìn)去索引假脫機(jī),當(dāng)SELECT * FROM managers的時(shí)候,直接到索引假脫機(jī)里取數(shù)據(jù)就可以了

1 SELECT * FROM [managers]

斷定運(yùn)算符在這里的作用是判斷是否超過(guò)系統(tǒng)循環(huán)次數(shù)造成死循環(huán),如果我們加上OPTION (MAXRECURSION 0)

斷定運(yùn)算符就會(huì)消失

 1 USE [AdventureWorks]
 2 GO
 3 WITH managers AS(
 4 SELECT [EmployeeID],[ManagerID]
 5 from [HumanResources].[Employee]
 6 WHERE [ManagerID] IS NULL
 7 UNION ALL
 8 SELECT e.[EmployeeID],e.[ManagerID]
 9 from [managers] m
10 JOIN [HumanResources].[Employee] e
11 ON e.[ManagerID]=m.[EmployeeID]
12 )
13 
14 SELECT * FROM [managers] OPTION (MAXRECURSION 0)


萬(wàn)圣節(jié)問(wèn)題

網(wǎng)上有兩篇文章介紹了這個(gè)問(wèn)題

園子里的這篇文章介紹非常不深入,看了之后還是不明白

http://www.cnblogs.com/xwdreamer/archive/2012/05/28/2522404.html

simple-talk網(wǎng)站的文章就介紹得非常清晰

https://www.simple-talk.com/sql/learn-sql-server/operator-of-the-week---spools,-eager-spool/

在介紹之前先來(lái)做一個(gè)小實(shí)驗(yàn)

下面SQL腳本建立一個(gè)非聚集索引表,并且非聚集索引的第一個(gè)字段是salary 并且按salary升序排序!!!

 1 USE [Spool]
 2 GO
 3 
 4 CREATE TABLE nct(id INT IDENTITY(1,1),NAME VARCHAR(30), salary INT);
 5 GO
 6 --建立非聚集索引  切記:非聚集索引的第一個(gè)字段是salary 并且按salary升序排序!!!
 7 CREATE  INDEX ix_nct ON nct(salary ASC,[ID],[NAME]) 
 8 GO
 9  
10 --插入數(shù)據(jù)
11 INSERT INTO [dbo].[nct] ( [NAME],[salary] )
12 SELECT '小明', 1 UNION ALL
13 SELECT '小華', 2 UNION ALL
14 SELECT '小芳', 3
15 GO
16 
17 SELECT * FROM [dbo].[nct]

View Code

我們看一下非聚集索引頁(yè)

 1 CREATE TABLE DBCCResult (
 2 PageFID NVARCHAR(200),
 3 PagePID NVARCHAR(200),
 4 IAMFID NVARCHAR(200),
 5 IAMPID NVARCHAR(200),
 6 ObjectID NVARCHAR(200),
 7 IndexID NVARCHAR(200),
 8 PartitionNumber NVARCHAR(200),
 9 PartitionID NVARCHAR(200),
10 iam_chain_type NVARCHAR(200),
11 PageType NVARCHAR(200),
12 IndexLevel NVARCHAR(200),
13 NextPageFID NVARCHAR(200),
14 NextPagePID NVARCHAR(200),
15 PrevPageFID NVARCHAR(200),
16 PrevPagePID NVARCHAR(200)
17 )
18 
19 --TRUNCATE TABLE [dbo].[DBCCResult]
20 
21 INSERT INTO DBCCResult EXEC ('DBCC IND(Spool,nct,-1) ')
22 
23 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
24 
25 DBCC TRACEON(3604,-1)
26 GO
27 DBCC PAGE(Spool,1,47,3) 
28 GO

View Code

非聚集索引按照Salary字段升序排序

我們用SQL語(yǔ)句update一下小華的Salary

1 UPDATE nct SET Salary = 4
2 WHERE [NAME]='小華'

這里是按照非聚集索引的Range Scan讀取出結(jié)果的:SQLSERVER中的ALLOCATION SCAN和RANGE SCAN

再看一下非聚集索引頁(yè)面

我們看一下update前和update后非聚集索引頁(yè)面的變化

可以看到,update之后非聚集索引馬上根據(jù)非聚集索引鍵(Salary字段)重新進(jìn)行升序排序

--------------------------------------------------------------------------------------------

使用下面SQL腳本建立測(cè)試環(huán)境

 1 USE [Spool]
 2 GO
 3 
 4 
 5 --建表
 6 CREATE TABLE Halloween
 7 (
 8   ID INT IDENTITY(1, 1)
 9          PRIMARY KEY ,
10   Name VARCHAR(30) ,
11   Salary NUMERIC(18, 2),
12   Remark NVARCHAR(3000)
13 )
14 GO
15  
16 --插入數(shù)據(jù)
17 INSERT INTO [dbo].[Halloween] ( [Name], [Salary], [Remark] )
18 SELECT '小明',1,replicate('a', 3000) UNION ALL
19 SELECT '小方',2,replicate('a', 3000) 
20 
21 
22 
23 
24 --建立非聚集索引
25 CREATE NONCLUSTERED INDEX ix_Halloween ON Halloween(Salary ASC)
26 GO
27 
28 --查詢
29 SELECT * FROM Halloween
30 GO

View Code

我們用下面SQL語(yǔ)句看一下聚集索引頁(yè)面和非聚集索引頁(yè)面

 1 CREATE TABLE DBCCResult (
 2 PageFID NVARCHAR(200),
 3 PagePID NVARCHAR(200),
 4 IAMFID NVARCHAR(200),
 5 IAMPID NVARCHAR(200),
 6 ObjectID NVARCHAR(200),
 7 IndexID NVARCHAR(200),
 8 PartitionNumber NVARCHAR(200),
 9 PartitionID NVARCHAR(200),
10 iam_chain_type NVARCHAR(200),
11 PageType NVARCHAR(200),
12 IndexLevel NVARCHAR(200),
13 NextPageFID NVARCHAR(200),
14 NextPagePID NVARCHAR(200),
15 PrevPageFID NVARCHAR(200),
16 PrevPagePID NVARCHAR(200)
17 )
18 
19 --TRUNCATE TABLE [dbo].[DBCCResult]
20 INSERT INTO DBCCResult EXEC ('DBCC IND(spool,Halloween,-1) ')
21 
22 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
23 
24 
25 DBCC TRACEON(3604,-1)
26 GO
27 DBCC PAGE(spool,1,184,3) 
28 GO
29 DBCC PAGE(spool,1,93,3) 
30 GO

View Code

聚集索引頁(yè)面

非聚集索引頁(yè)面

我們update一下Salary等于1的那位員工的工資

1 UPDATE Halloween SET Salary = 2.5
2 FROM Halloween 
3 WHERE Salary =1

再看一下聚集索引頁(yè)面和非聚集索引頁(yè)面

聚集索引頁(yè)面

非聚集索引頁(yè)面

非聚集索引馬上按照非聚集索引鍵(Salary字段)進(jìn)行重新排序

這里似乎沒(méi)有什么問(wèn)題,我們drop掉Halloween表,并重新建立測(cè)試環(huán)境

 1 USE [Spool]
 2 GO
 3 
 4 
 5 
 6 --建表
 7 CREATE TABLE Halloween
 8 (
 9   ID INT IDENTITY(1, 1)
10          PRIMARY KEY ,
11   Name VARCHAR(30) ,
12   Salary NUMERIC(18, 2),
13   Remark NVARCHAR(3000)
14 )
15 GO
16  
17 --插入數(shù)據(jù)
18 INSERT INTO [dbo].[Halloween] ( [Name], [Salary], [Remark] )
19 SELECT '小明',1,replicate('a', 3000) UNION ALL
20 SELECT '小方',2,replicate('a', 3000) 
21 
22 
23 
24 
25 --建立非聚集索引
26 CREATE NONCLUSTERED INDEX ix_Halloween ON Halloween(Salary ASC)
27 GO
28 
29 --查詢
30 SELECT * FROM Halloween
31 GO
32 
33 
34 
35 
36 
37 CREATE TABLE DBCCResult (
38 PageFID NVARCHAR(200),
39 PagePID NVARCHAR(200),
40 IAMFID NVARCHAR(200),
41 IAMPID NVARCHAR(200),
42 ObjectID NVARCHAR(200),
43 IndexID NVARCHAR(200),
44 PartitionNumber NVARCHAR(200),
45 PartitionID NVARCHAR(200),
46 iam_chain_type NVARCHAR(200),
47 PageType NVARCHAR(200),
48 IndexLevel NVARCHAR(200),
49 NextPageFID NVARCHAR(200),
50 NextPagePID NVARCHAR(200),
51 PrevPageFID NVARCHAR(200),
52 PrevPagePID NVARCHAR(200)
53 )
54 
55 --TRUNCATE TABLE [dbo].[DBCCResult]
56 INSERT INTO DBCCResult EXEC ('DBCC IND(spool,Halloween,-1) ')
57 
58 SELECT * FROM [dbo].[DBCCResult] ORDER BY [PageType] DESC 
59 
60 
61 DBCC TRACEON(3604,-1)
62 GO
63 DBCC PAGE(spool,1,184,3) 
64 GO
65 DBCC PAGE(spool,1,93,3) 
66 GO

View Code

這次我們使用下面update語(yǔ)句,記住一定要加WITH(INDEX=ix_Halloween)

1 USE [Spool]
2 GO
3 UPDATE Halloween SET Salary = [Salary]*2.5
4 FROM Halloween WITH(INDEX=ix_Halloween)
5 WHERE Salary <7

如果我們加了WITH(INDEX=ix_Halloween),SQLSERVER就會(huì)走非聚集索引查找

如果我們不加WITH(INDEX=ix_Halloween),SQLSERVER就會(huì)走聚集索引掃描

這里不討論加不加WITH(INDEX=ix_Halloween)的問(wèn)題

關(guān)鍵我們加WITH(INDEX=ix_Halloween)就是為了讓SQLSERVER走非聚集索引

update了之后正常的結(jié)果應(yīng)該是這樣的

為什麼會(huì)這樣?

還記得剛才我們說(shuō)到了非聚集索引更新了之后馬上進(jìn)行排序嗎?

用下面的圖來(lái)表示應(yīng)該會(huì)比較清楚

SQLSERVER使用Table Spool來(lái)解決萬(wàn)圣節(jié)問(wèn)題

先將非聚集索引的數(shù)據(jù)放進(jìn)去Table Spool(臨時(shí)表)里,然后逐行逐行掃描臨時(shí)表,這樣就不會(huì)遇到非聚集索引更新后馬上進(jìn)行排序的問(wèn)題了

使用Table Spool后就能夠得到正確結(jié)果

為什麼不用Index Spool而用Table Spool?

之前我們說(shuō)過(guò)Index Spool在tempdb數(shù)據(jù)庫(kù)里建立臨時(shí)的非聚集索引,把非聚集索引里的數(shù)據(jù)

放進(jìn)去非聚集索引里,那不是會(huì)繼續(xù)遇到萬(wàn)圣節(jié)問(wèn)題???

下面這個(gè)SQL語(yǔ)句也是使用了Table Spool來(lái)避免萬(wàn)圣節(jié)問(wèn)題

1 USE [AdventureWorks]
2 GO
3 UPDATE  s
4 SET     [Name] = 'Z' + [Name]
5 FROM    Production.ProductSubcategory AS s WITH ( INDEX ( [AK_ProductSubcategory_Name] ) )
6 WHERE   [Name] >= 'N'

萬(wàn)圣節(jié)問(wèn)題

update數(shù)據(jù)的時(shí)候,如果update的是非聚集索引的第一個(gè)字段(即非聚集索引鍵)的時(shí)候并且走的是非聚集索引掃描/查找
都有可能引起萬(wàn)圣節(jié)問(wèn)題
SQLSERVER的解決方法是把非聚集索引里的數(shù)據(jù)全部移到Tabel Spool(Eager)里
防止由于更新非聚集索引的非聚集索引鍵而引起的非聚集索引重新排序,造成數(shù)據(jù)更新錯(cuò)誤的問(wèn)題

然后,其實(shí)Index Spool又好Table Spool又好,都是屬于臨時(shí)表的一種

類似案例
https://time.geekbang.org/column/article/80801
insert into t(c,d) (select c+1, d from t force index(c) order by c desc limit 1);
至于這個(gè)語(yǔ)句的執(zhí)行為什么需要臨時(shí)表,原因是這類一邊遍歷數(shù)據(jù),一邊更新數(shù)據(jù)的情況,如果讀出來(lái)的數(shù)據(jù)直接寫回原表,
就可能在遍歷過(guò)程中,讀到剛剛插入的記錄,新插入的記錄如果參與計(jì)算邏輯,就跟語(yǔ)義不符。

--建立非聚集索引
CREATE NONCLUSTERED INDEX ix_Halloween ON Halloween(Salary ASC)
GO
UPDATE Halloween SET Salary = [Salary]*2.5
FROM Halloween WITH(INDEX=ix_Halloween)
WHERE Salary <7

這類場(chǎng)景,其實(shí)都可以歸納為一邊遍歷數(shù)據(jù),一邊更新數(shù)據(jù)的情況,通用解決方案都是使用臨時(shí)表,先暫存現(xiàn)有的表數(shù)據(jù),然后對(duì)臨時(shí)表的數(shù)據(jù)進(jìn)行計(jì)算,計(jì)算完之后再更新回去原表


總結(jié)

實(shí)際上這些假脫機(jī)運(yùn)算符的本質(zhì)跟臨時(shí)表和表變量是一樣的,都是以空間換時(shí)間,以達(dá)到性能上的平衡!

文章最后面附上MSDN里的SQLSERVER所有的執(zhí)行計(jì)劃(邏輯運(yùn)算符和物理運(yùn)算符)

參考文章:

http://www.scarydba.com/2009/09/09/spools-in-execution-plans/

https://www.simple-talk.com/sql/learn-sql-server/operator-of-the-week---spools,-eager-spool/

http://sqlblog.com/blogs/rob_farley/archive/2013/06/11/spooling-in-sql-execution-plans.aspx

如有不對(duì)的地方,歡迎大家拍磚o(∩_∩)o



Showplan 邏輯運(yùn)算符和物理運(yùn)算符參考

操作說(shuō)明


本節(jié)介紹了各個(gè)邏輯運(yùn)算符和物理運(yùn)算符。

圖形執(zhí)行計(jì)劃圖標(biāo)

Showplan 運(yùn)算符

說(shuō)明

無(wú)

Aggregate

Aggregate運(yùn)算符計(jì)算包含 MIN、MAX、SUM、COUNT 或 AVG 的表達(dá)式。Aggregate既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Arithmetic Expression

Arithmetic Expression運(yùn)算符根據(jù)行中的現(xiàn)有值計(jì)算新值。SQL Server 2012 中不使用Arithmetic Expression,

Assert

Assert運(yùn)算符用于驗(yàn)證條件。例如,驗(yàn)證引用完整性或確保標(biāo)量子查詢返回一行。對(duì)于每個(gè)輸入行,Assert運(yùn)算符都要計(jì)算執(zhí)行計(jì)劃的Argument列中的表達(dá)式。如果此表達(dá)式的值為 NULL,則通過(guò)Assert運(yùn)算符傳遞該行,并且查詢執(zhí)行將繼續(xù)。如果此表達(dá)式的值非 Null,則將產(chǎn)生相應(yīng)的錯(cuò)誤。Assert運(yùn)算符是一個(gè)物理運(yùn)算符。

Assign

Assign運(yùn)算符將表達(dá)式的值或常量分配給變量。Assign是一個(gè)語(yǔ)言元素。

無(wú)

Asnyc Concat

Asnyc Concat運(yùn)算符僅用于遠(yuǎn)程查詢(分布式查詢)。它有n個(gè)子節(jié)點(diǎn)和一個(gè)父節(jié)點(diǎn)。通常,某些子節(jié)點(diǎn)是參與分布式查詢的遠(yuǎn)程計(jì)算機(jī)。Asnyc Concat同時(shí)向所有子節(jié)點(diǎn)發(fā)出open()調(diào)用,然后將位圖應(yīng)用于每個(gè)子節(jié)點(diǎn)。對(duì)于為 1 的每個(gè)位,Async Concat按需向父節(jié)點(diǎn)發(fā)送輸出行。

Bitmap

SQL Server 使用Bitmap運(yùn)算符來(lái)實(shí)現(xiàn)并行查詢計(jì)劃中的位圖篩選。在將行傳遞給另一個(gè)運(yùn)算符(如Parallelism運(yùn)算符)之前,通過(guò)消除無(wú)法生成任何聯(lián)接記錄的鍵值的行,位圖篩選可提高查詢的執(zhí)行速度。位圖篩選器使用運(yùn)算符樹(shù)某部分的表中一組值的簡(jiǎn)潔表示形式來(lái)篩選位于該樹(shù)另一部分的第二張表中的行。通過(guò)在查詢中預(yù)先刪除不必要的行,后續(xù)運(yùn)算符將處理較少的行,從而提高查詢的整體性能。優(yōu)化器將確定位圖的選擇性何時(shí)可滿足使用條件以及在哪些運(yùn)算符上應(yīng)用篩選器。Bitmap是一個(gè)物理運(yùn)算符。

Bitmap Create

Bitmap Create運(yùn)算符出現(xiàn)在創(chuàng)建位圖的顯示計(jì)劃輸出中。Bitmap Create是一個(gè)邏輯運(yùn)算符。

Bookmark Lookup

Bookmark Lookup運(yùn)算符使用書(shū)簽(行 ID 或聚集鍵)在表或聚集索引內(nèi)查找相應(yīng)的行。Argument列包含書(shū)簽標(biāo)簽,用于在表或聚集索引內(nèi)查找行。Argument列還包含要查找的行所在的表或聚集索引的名稱。如果Argument列中出現(xiàn) WITH PREFETCH 子句,則表示查詢處理器已決定在表或聚集索引內(nèi)查找書(shū)簽時(shí)將使用異步預(yù)提取(預(yù)讀)作為最佳選擇。

SQL Server 2012 中不使用Bookmark Lookup,而由Clustered Index Seek和RID Lookup提供書(shū)簽查找功能。Key Lookup運(yùn)算符也提供此功能。

無(wú)

Branch Repartition

在并行查詢計(jì)劃中,有時(shí)存在迭代器的概念性區(qū)域。此類區(qū)域中的所有迭代器都可通過(guò)并行線程執(zhí)行。這些區(qū)域本身必須串行執(zhí)行。單個(gè)區(qū)域內(nèi)的某些Parallelism迭代器稱為Branch Repartition。兩個(gè)這樣的區(qū)域邊界上的Parallelism迭代器稱為Segment Repartition。Branch Repartition和Segment Repartition是邏輯運(yùn)算符。

無(wú)

Broadcast

Broadcast有一個(gè)子節(jié)點(diǎn)和n個(gè)父節(jié)點(diǎn)。Broadcast根據(jù)使用者的請(qǐng)求將其輸入行發(fā)送給多個(gè)使用者。每個(gè)使用者都將獲得所有行。例如,如果所有使用者都是哈希聯(lián)接的生成端,則將生成n份哈希表。

Build Hash

指示為 xVelocity 內(nèi)存優(yōu)化的列存儲(chǔ)索引生成批處理哈希表。

無(wú)

Cache

Cache是一個(gè)專門的Spool運(yùn)算符。它僅存儲(chǔ)一行數(shù)據(jù)。Cache是一個(gè)邏輯運(yùn)算符。SQL Server 2012 中不使用Cache

Clustered Index Delete

Clustered Index Delete運(yùn)算符可刪除查詢執(zhí)行計(jì)劃的 Argument 列指定的群集索引中的行。如果 Argument 列中存在 WHERE:() 謂詞,則僅刪除滿足該謂詞要求的行。Clustered Index Delete是一個(gè)物理運(yùn)算符。

Clustered Index Insert

Clustered Index InsertShowplan 運(yùn)算符可將其輸入中的行插入在 Argument 列指定的聚集索引中。Argument 列還包含一個(gè) SET:() 謂詞,用于指示為每一列設(shè)置的值。如果Clustered Index Insert的插入值沒(méi)有子項(xiàng),則插入的行來(lái)自Insert運(yùn)算符本身。Clustered Index Insert是一個(gè)物理運(yùn)算符。

Clustered Index Merge

Clustered Index Merge運(yùn)算符可將合并數(shù)據(jù)流應(yīng)用于聚集索引。該運(yùn)算符可在其Argument列中所指定的聚集索引中刪除、更新或插入行。執(zhí)行的實(shí)際操作取決于該運(yùn)算符的Argument列中指定的ACTION列的運(yùn)行時(shí)值。Clustered Index Merge是一個(gè)物理運(yùn)算符。

Clustered Index Scan

Clustered Index Scan運(yùn)算符會(huì)掃描查詢執(zhí)行計(jì)劃的 Argument 列中指定的聚集索引。存在可選 WHERE:() 謂詞時(shí),則只返回滿足該謂詞的那些行。如果 Argument 列包含 ORDERED 子句,則查詢處理器已請(qǐng)求按聚集索引排列行的順序返回行輸出。如果沒(méi)有 ORDERED 子句,存儲(chǔ)引擎將以最佳方式掃描索引,而無(wú)需對(duì)輸出進(jìn)行排序。Clustered Index Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Clustered Index Seek

Clustered Index Seek運(yùn)算符可以利用索引的查找功能從聚集索引中檢索行。Argument列包含所使用的聚集索引名稱和 SEEK:() 謂詞。存儲(chǔ)引擎僅使用索引來(lái)處理滿足此 SEEK:() 謂詞的行。它還包括 WHERE:() 謂詞,其中存儲(chǔ)引擎對(duì)滿足 SEEK:() 謂詞的所有行進(jìn)行計(jì)算,但此操作是可選的,并且不使用索引來(lái)完成此過(guò)程。

如果Argument列包含 ORDERED 子句,則表示查詢處理器已決定必須按聚集索引排序行的順序返回行。如果沒(méi)有 ORDERED 子句,存儲(chǔ)引擎將以最佳方式搜索索引,而不對(duì)輸出進(jìn)行必要的排序。若允許輸出保持順序,則效率可能比生成非排序輸出的效率低。出現(xiàn)關(guān)鍵字 LOOKUP 時(shí),將執(zhí)行書(shū)簽查找。在 SQL Server 2008 和更高版本中,Key Lookup運(yùn)算符提供書(shū)簽查找功能。Clustered Index Seek既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Clustered Index Update

Clustered Index Update運(yùn)算符更新Argument列指定的聚集索引中的輸入行。如果存在 WHERE:() 謂詞,則只更新那些滿足此謂詞要求的行。如果存在 SET:() 謂詞,則將每個(gè)更新的列設(shè)置為該值。如果存在 DEFINE:() 謂詞,則列出此運(yùn)算符定義的值。可以在 SET 子句中、該運(yùn)算符內(nèi)的其他位置和該查詢內(nèi)的其他位置引用這些值。Clustered Index Update既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Collapse

Collapse運(yùn)算符用于優(yōu)化更新處理。執(zhí)行更新時(shí),可以將該更新操作拆分(使用Split運(yùn)算符)成為刪除和插入操作。Argument列包含一個(gè)指定鍵列列表的 GROUP BY:() 子句。如果查詢處理器遇到刪除和插入相同鍵值的相鄰行,則會(huì)用一個(gè)更有效的更新操作替換這些單獨(dú)的操作。Collapse既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Columnstore Index Scan

Columnstore Index Scan運(yùn)算符會(huì)掃描查詢執(zhí)行計(jì)劃的Argument列中指定的列存儲(chǔ)索引。

Compute Scalar

Compute Scalar運(yùn)算符通過(guò)對(duì)表達(dá)式求值來(lái)生成計(jì)算標(biāo)量值。該值可以返回給用戶、在查詢中的其他位置引用或二者皆可。例如,在篩選謂詞或聯(lián)接謂詞中就會(huì)出現(xiàn)二者皆可的情況。Compute Scalar既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

在 SET STATISTICS XML 生成的顯示計(jì)劃中出現(xiàn)的Compute Scalar運(yùn)算符可能不包含RunTimeInformation元素。在圖形顯示計(jì)劃中,當(dāng)已在 SQL Server Management Studio 中選中“包括實(shí)際的執(zhí)行計(jì)劃”選項(xiàng)時(shí),“實(shí)際行”、“實(shí)際重新綁定次數(shù)”和“實(shí)際重繞次數(shù)”可能不會(huì)出現(xiàn)在“屬性”窗口中。當(dāng)出現(xiàn)這種情況時(shí),意味著雖然編譯過(guò)的查詢計(jì)劃中使用了這些運(yùn)算符,但在運(yùn)行時(shí)查詢計(jì)劃中,它們的作用是由其他運(yùn)算符實(shí)現(xiàn)的。另外,請(qǐng)注意,SET STATISTICS PROFILE 生成的顯示計(jì)劃輸出中的執(zhí)行數(shù)等于 SET STATISTICS XML 生成的顯示計(jì)劃中的重新綁定次數(shù)和重繞次數(shù)的總和。

Concatenation

Concatenation運(yùn)算符掃描多個(gè)輸入,并返回每個(gè)掃描的行。Concatenation通常用于實(shí)現(xiàn) Transact-SQL UNION ALL 結(jié)構(gòu)。Concatenation物理運(yùn)算符有兩個(gè)或多個(gè)輸入,有一個(gè)輸出。Concatenation 將行從第一個(gè)輸入流復(fù)制到輸出流,然后對(duì)其他輸入流重復(fù)進(jìn)行此操作。Concatenation既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Constant Scan

Constant Scan運(yùn)算符可將一個(gè)或多個(gè)常量行引入到查詢中。Compute Scalar運(yùn)算符通常在Constant Scan之后使用,以將列添加到Constant Scan運(yùn)算符生成的行中。

Convert

Convert運(yùn)算符將標(biāo)量數(shù)據(jù)類型轉(zhuǎn)換為另一種類型。Convert是一個(gè)語(yǔ)言元素。

無(wú)

Cross Join

Cross Join運(yùn)算符將第一個(gè)(頂端)輸入中的每一行與第二個(gè)(底端)輸入中的每一行聯(lián)接在一起。Cross Join是一個(gè)邏輯運(yùn)算符。

catchall

生成圖形顯示計(jì)劃的邏輯找不到迭代器的合適圖標(biāo)時(shí),將顯示通用圖標(biāo)。通用圖標(biāo)不一定指示存在錯(cuò)誤。有三種通用圖標(biāo):藍(lán)色(用于迭代器)、橙色(用于游標(biāo))和綠色(用于 Transact-SQL 語(yǔ)言元素)。

無(wú)

Cursor

Cursor邏輯運(yùn)算符和物理運(yùn)算符用于描述涉及游標(biāo)操作的查詢或更新的執(zhí)行方式。其中物理運(yùn)算符描述用于處理游標(biāo)(如使用鍵集驅(qū)動(dòng)游標(biāo))的物理實(shí)現(xiàn)算法。游標(biāo)執(zhí)行過(guò)程的每一步都涉及物理運(yùn)算符。而邏輯運(yùn)算符描述游標(biāo)的屬性,如游標(biāo)是只讀。

邏輯運(yùn)算符包括 Asynchronous、Optimistic、Primary、Read Only、Scroll Locks、Secondary 和 Synchronous。

物理運(yùn)算符包括 Dynamic、Fetch Query、Keyset、Population Query、Refresh Query 和 Snapshot。

Declare

Declare運(yùn)算符用于分配查詢計(jì)劃中的局部變量。Declare是一個(gè)語(yǔ)言元素。

Delete

Delete運(yùn)算符將從對(duì)象中刪除滿足Argument列內(nèi)的可選謂詞的行。

Deleted Scan

Deleted Scan運(yùn)算符在觸發(fā)器中掃描刪除的表。

無(wú)

Distinct

Distinct運(yùn)算符可以從行集或值集中刪除重復(fù)項(xiàng)。Distinct是一個(gè)邏輯運(yùn)算符。

無(wú)

Distinct Sort

Distinct Sort邏輯運(yùn)算符將對(duì)輸入進(jìn)行掃描,刪除重復(fù)項(xiàng)并按Argument列的 DISTINCT ORDER BY:() 謂詞中指定的列進(jìn)行排序。Distinct Sort是一個(gè)邏輯運(yùn)算符。

Distribute Streams

Distribute Streams運(yùn)算符僅用于并行查詢計(jì)劃。Distribute Streams運(yùn)算符接收記錄的單個(gè)輸入流,并生成多個(gè)輸出流。記錄的內(nèi)容和格式不會(huì)改變。輸入流中的每個(gè)記錄都將在某個(gè)輸出流中顯示。此運(yùn)算符在輸出流中自動(dòng)保留輸入記錄的相對(duì)順序。通常情況下,使用哈希操作確定特定輸入記錄所屬的輸出流。

如果將輸出分區(qū),那么Argument列會(huì)包含 PARTITION COLUMNS:() 謂詞和分區(qū)列。Distribute Streams是一個(gè)邏輯運(yùn)算符。

Dynamic

Dynamic運(yùn)算符使用可以查看其他游標(biāo)所做的任何更改的游標(biāo)。

Eager Spool

Eager Spool運(yùn)算符獲取整個(gè)輸入,并將每行存儲(chǔ)在tempdb數(shù)據(jù)庫(kù)中存儲(chǔ)的隱藏臨時(shí)對(duì)象中。如果重繞該運(yùn)算符(例如通過(guò)Nested Loops運(yùn)算符重繞),但不需要任何重新綁定,則將使用假脫機(jī)數(shù)據(jù),而不用重新掃描輸入。如果需要重新綁定,將丟棄假脫機(jī)數(shù)據(jù),并通過(guò)重新掃描(重新綁定的)輸入重新生成假脫機(jī)對(duì)象。Eager Spool運(yùn)算符按“急切”方式生成自己的假脫機(jī)文件:當(dāng)假脫機(jī)的父運(yùn)算符請(qǐng)求第一行時(shí),假脫機(jī)運(yùn)算符將獲取所有來(lái)自其輸入運(yùn)算符的行并將其存儲(chǔ)在假脫機(jī)中。Eager Spool是一個(gè)邏輯運(yùn)算符。

Fetch Query

當(dāng)對(duì)游標(biāo)發(fā)出提取命令時(shí),F(xiàn)etch Query運(yùn)算符將檢索行。

Filter

Filter運(yùn)算符掃描輸入,僅返回那些符合Argument列中的篩選表達(dá)式(謂詞)的行。

無(wú)

Flow Distinct

Flow Distinct邏輯運(yùn)算符用于通過(guò)掃描輸入來(lái)刪除重復(fù)項(xiàng)。雖然Distinct運(yùn)算符在生成任何輸入前使用所有的輸入,但FlowDistinct運(yùn)算符在從輸入獲得行時(shí)返回每行(除非該行是一個(gè)重復(fù)項(xiàng),若是這樣則刪除該行)。

無(wú)

Full Outer Join

Full Outer Join邏輯運(yùn)算符從第一個(gè)(頂端)輸入中與第二個(gè)(底端)輸入相聯(lián)接的行中返回每個(gè)滿足聯(lián)接謂詞的行。它還可以從下列輸入返回行:

在第二個(gè)輸入中沒(méi)有匹配項(xiàng)的第一個(gè)輸入。

在第一個(gè)輸入中沒(méi)有匹配項(xiàng)的第二個(gè)輸入。

不包含匹配值的輸入將作為空值返回。Full Outer Join是一個(gè)邏輯運(yùn)算符。

Gather Streams

Gather Streams運(yùn)算符僅用在并行查詢計(jì)劃中。Gather Streams運(yùn)算符處理幾個(gè)輸入流并通過(guò)組合這幾個(gè)輸入流生成單個(gè)記錄輸出流。不更改記錄的內(nèi)容和格式。如果此運(yùn)算符保留順序,則所有的輸入流都必須有序。如果輸出已排序,則Argument列包含一個(gè) ORDER BY:() 謂詞和正在排序的列名稱。Gather Streams是一個(gè)邏輯運(yùn)算符。

Hash Match

Hash Match運(yùn)算符通過(guò)計(jì)算其生成輸入中每行的哈希值生成哈希表。HASH:() 謂詞以及一個(gè)用于創(chuàng)建哈希值的列的列表出現(xiàn)在Argument列內(nèi)。然后,該謂詞為每個(gè)探測(cè)行(如果適用)計(jì)算哈希值(使用相同的哈希函數(shù))并在哈希表內(nèi)查找匹配項(xiàng)。如果存在殘留謂詞(由Argument列中的 RESIDUAL:() 標(biāo)識(shí)),則還須滿足此殘留謂詞,只有這樣行才能被視為是匹配項(xiàng)。行為取決于所執(zhí)行的邏輯操作:

對(duì)于聯(lián)接,使用第一個(gè)(頂端)輸入生成哈希表,使用第二個(gè)(底端)輸入探測(cè)哈希表。按聯(lián)接類型規(guī)定的模式輸出匹配項(xiàng)(或不匹配項(xiàng))。如果多個(gè)聯(lián)接使用相同的聯(lián)接列,這些操作將分組為一個(gè)哈希組。

對(duì)于非重復(fù)或聚合運(yùn)算符,使用輸入生成哈希表(刪除重復(fù)項(xiàng)并計(jì)算聚合表達(dá)式)。生成哈希表時(shí),掃描該表并輸出所有項(xiàng)。

對(duì)于 union 運(yùn)算符,使用第一個(gè)輸入生成哈希表(刪除重復(fù)項(xiàng))。使用第二個(gè)輸入(它必須沒(méi)有重復(fù)項(xiàng))探測(cè)哈希表,返回所有沒(méi)有匹配項(xiàng)的行,然后掃描該哈希表并返回所有項(xiàng)。

Hash Match是一個(gè)物理運(yùn)算符。

If

If運(yùn)算符執(zhí)行基于表達(dá)式的有條件處理。If是一個(gè)語(yǔ)言元素。

無(wú)

Inner Join

Inner Join邏輯運(yùn)算符返回滿足第一個(gè)(頂端)輸入與第二個(gè)(底端)輸入所組成的聯(lián)接的每一行。

Insert

Insert邏輯運(yùn)算符將每行從其輸入插入Argument列內(nèi)指定的對(duì)象中。相應(yīng)的物理運(yùn)算符為Table Insert、Index Insert或Clustered Index Insert運(yùn)算符。

Inserted Scan

Inserted Scan運(yùn)算符掃描插入的表。Inserted Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Intrinsic

Intrinsic運(yùn)算符調(diào)用內(nèi)部 Transact-SQL 函數(shù)。Intrinsic是一個(gè)語(yǔ)言元素。

Iterator

生成圖形顯示計(jì)劃的邏輯找不到Iterator的合適圖標(biāo)時(shí),將顯示通用圖標(biāo)。通用圖標(biāo)不一定指示存在錯(cuò)誤。有三種通用圖標(biāo):藍(lán)色(用于迭代器)、橙色(用于游標(biāo))和綠色(用于 Transact-SQL 語(yǔ)言構(gòu)造)。

Key Lookup

Key Lookup運(yùn)算符是在具有聚集索引的表上進(jìn)行的書(shū)簽查找。Argument列包含聚集索引的名稱和用來(lái)在聚集索引中查找行的聚集鍵。Key Lookup通常帶有Nested Loops運(yùn)算符。如果Argument列中出現(xiàn) WITH PREFETCH 子句,則表示查詢處理器已決定在聚集索引內(nèi)查找書(shū)簽時(shí)將使用異步預(yù)提取(預(yù)讀)作為最佳選擇。

在查詢計(jì)劃中使用Key Lookup運(yùn)算符表明該查詢可能會(huì)從性能優(yōu)化中獲益。例如,添加涵蓋索引可能會(huì)提高查詢性能。

Keyset

Keyset運(yùn)算符使用的游標(biāo)可用于查看其他用戶所做的更新,而不能查看其他用戶所做的插入。

Language Element

生成圖形顯示計(jì)劃的邏輯找不到Language Element的合適圖標(biāo)時(shí),將顯示通用圖標(biāo)。通用圖標(biāo)不一定指示存在錯(cuò)誤。有三種通用圖標(biāo):藍(lán)色(用于迭代器)、橙色(用于游標(biāo))和綠色(用于 Transact-SQL 語(yǔ)言構(gòu)造)。

Lazy Spool

Lazy Spool邏輯運(yùn)算符將其輸入中的每一行存儲(chǔ)到tempdb數(shù)據(jù)庫(kù)內(nèi)存儲(chǔ)的隱藏臨時(shí)對(duì)象中。如果重繞該運(yùn)算符(例如通過(guò)Nested Loops運(yùn)算符重繞),但不需要任何重新綁定,則將使用假脫機(jī)數(shù)據(jù),而不用重新掃描輸入。如果需要重新綁定,則將放棄假脫機(jī)數(shù)據(jù),并通過(guò)重新掃描(重新綁定的)輸入重新生成假脫機(jī)對(duì)象。Lazy Spool運(yùn)算符以“遲緩”方式生成其假脫機(jī)文件,即每當(dāng)假脫機(jī)父運(yùn)算符請(qǐng)求一行時(shí),假脫機(jī)運(yùn)算符便從其輸入運(yùn)算符獲取一行,然后將該行存儲(chǔ)在假脫機(jī)中,而不是一次處理所有行。Lazy Spool 是一個(gè)邏輯運(yùn)算符。

無(wú)

Left Anti Semi Join

當(dāng)?shù)诙€(gè)(底端)輸入中沒(méi)有匹配行時(shí),Left Anti Semi Join運(yùn)算符返回第一個(gè)(頂端)輸入中的每一行。如果Argument列內(nèi)不存在任何聯(lián)接謂詞,則每行都是一個(gè)匹配行。Left Anti Semi Join是一個(gè)邏輯運(yùn)算符。

無(wú)

Left Outer Join

Left Outer Join運(yùn)算符返回滿足第一個(gè)(頂端)輸入與第二個(gè)(底端)輸入聯(lián)接的每一行。它還返回任何在第二個(gè)輸入中沒(méi)有匹配行的第一個(gè)輸入中的行。第二個(gè)輸入中的非匹配行作為空值返回。如果Argument列內(nèi)不存在任何聯(lián)接謂詞,則每行都是一個(gè)匹配行。Left Outer Join是一個(gè)邏輯運(yùn)算符。

無(wú)

Left Semi Join

當(dāng)?shù)诙€(gè)(底端)輸入中有匹配行時(shí),Left Semi Join運(yùn)算符返回第一個(gè)(頂端)輸入中的每行。如果Argument列內(nèi)不存在任何聯(lián)接謂詞,則每行都是一個(gè)匹配行。Left Semi Join是一個(gè)邏輯運(yùn)算符。

Log Row Scan

Log Row Scan運(yùn)算符用于掃描事務(wù)日志。Log Row Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Merge Interval

Merge Interval運(yùn)算符可合并多個(gè)(可能重疊的)間隔以得出最小的不重疊間隔,然后將其用于查找索引項(xiàng)。此運(yùn)算符通常出現(xiàn)在Constant Scan運(yùn)算符中的一個(gè)或多個(gè)Compute Scalar運(yùn)算符上方,后者運(yùn)算符構(gòu)造了此運(yùn)算符所合并的間隔(表示為一行中的多個(gè)列)。Merge Interval既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Merge Join

Merge Join運(yùn)算符執(zhí)行內(nèi)部聯(lián)接、左外部聯(lián)接、左半部聯(lián)接、左反半部聯(lián)接、右外部聯(lián)接、右半部聯(lián)接、右反半部聯(lián)接和聯(lián)合邏輯運(yùn)算。

Argument列中,如果操作執(zhí)行一對(duì)多聯(lián)接,則Merge Join運(yùn)算符將包含 MERGE:() 謂詞;如果操作執(zhí)行多對(duì)多聯(lián)接,則該運(yùn)算符將包含 MANY-TO-MANY MERGE:() 謂詞。Argument列還包含一個(gè)用于執(zhí)行操作的列的列表,該列表以逗號(hào)分隔。Merge Join運(yùn)算符要求在各自的列上對(duì)兩個(gè)輸入進(jìn)行排序,這可以通過(guò)在查詢計(jì)劃中插入顯式排序操作來(lái)實(shí)現(xiàn)。如果不需要顯式排序(例如,如果數(shù)據(jù)庫(kù)內(nèi)有合適的 B 樹(shù)索引或可以對(duì)多個(gè)操作(如合并聯(lián)接和對(duì)匯總分組)使用排序順序),則合并聯(lián)接尤其有效。Merge Join是一個(gè)物理運(yùn)算符。

Nested Loops

Nested Loops運(yùn)算符執(zhí)行內(nèi)部聯(lián)接、左外部聯(lián)接、左半部聯(lián)接和左反半部聯(lián)接邏輯運(yùn)算。Nested Loops 聯(lián)接通常使用索引在內(nèi)部表中搜索外部表的每一行。根據(jù)預(yù)計(jì)的開(kāi)銷,查詢處理器決定是否對(duì)外部輸入進(jìn)行排序來(lái)改變內(nèi)部輸入索引的搜索位置。將基于所執(zhí)行的邏輯操作返回所有滿足Argument列內(nèi)的(可選)謂詞的行。Nested Loops是一個(gè)物理運(yùn)算符。

Nonclustered Index Delete

Nonclustered Index Delete運(yùn)算符通過(guò)Argument列中指定的非聚集索引刪除輸入行。Nonclustered Index Delete是一個(gè)物理運(yùn)算符。

Index Insert

Index Insert運(yùn)算符用于將行從其輸入插入到Argument列中指定的非聚集索引中。Argument列還包含一個(gè) SET:() 謂詞,用于指示為每一列設(shè)置的值。Index Insert是一個(gè)物理運(yùn)算符。

Index Scan

Index Scan運(yùn)算符從Argument列中指定的非聚集索引中檢索所有行。如果可選的 WHERE:() 謂詞出現(xiàn)在Argument列中,則僅返回滿足此謂詞的那些行。Index Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Index Seek

Index Seek運(yùn)算符利用索引的查找功能從非聚集索引中檢索行。Argument列包含所使用的非聚集索引的名稱。它還包括 SEEK:() 謂詞。存儲(chǔ)引擎僅使用索引來(lái)處理滿足 SEEK:() 謂詞的行。它可能還包含一個(gè) WHERE:() 謂詞,其中存儲(chǔ)引擎對(duì)滿足 SEEK:() 謂詞的所有行進(jìn)行計(jì)算(不使用索引來(lái)完成)。如果Argument列包含 ORDERED 子句,則表示查詢處理器已決定必須按非聚集索引排序行的順序返回行。如果沒(méi)有 ORDERED 子句,則存儲(chǔ)引擎將以最佳方式(不保證對(duì)輸出排序)搜索索引。如果讓輸出保持其順序,則效率可能低于生成非排序輸出。Index Seek既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Index Spool

Index Spool物理運(yùn)算符在Argument列中包含 SEEK:() 謂詞。Index Spool運(yùn)算符掃描其輸入行,將每行的副本放置在隱藏的假脫機(jī)文件(存儲(chǔ)在tempdb數(shù)據(jù)庫(kù)中且只在查詢的生存期內(nèi)存在)中,并為這些行創(chuàng)建非聚集索引。這樣可以使用索引的查找功能來(lái)僅輸出那些滿足 SEEK:() 謂詞的行。如果重繞該運(yùn)算符(例如通過(guò)Nested Loops運(yùn)算符重繞),但不需要任何重新綁定,則將使用假脫機(jī)數(shù)據(jù),而不用重新掃描輸入。

Nonclustered Index Update

Nonclustered Index Update物理運(yùn)算符用于更新Argument列內(nèi)指定的非聚集索引中的輸入行。如果存在 SET:() 謂詞,則將每個(gè)更新的列設(shè)置為該值。Nonclustered Index Update是一個(gè)物理運(yùn)算符。

Online Index Insert

Online Index Insert物理運(yùn)算符指示索引創(chuàng)建、更改或刪除操作是在線執(zhí)行的。也就是說(shuō),基礎(chǔ)表數(shù)據(jù)在索引操作期間仍然對(duì)用戶可用。

無(wú)

Parallelism

Parallelism運(yùn)算符執(zhí)行分發(fā)流、收集流和對(duì)流重新分區(qū)邏輯操作。Argument列可以包含一個(gè) PARTITION COLUMNS:() 謂詞和一個(gè)以逗號(hào)分隔的分區(qū)列的列表。Argument列還可以包含一個(gè) ORDER BY:() 謂詞,以列出分區(qū)過(guò)程中要保留排序順序的列。Parallelism是物理運(yùn)算符。

注意

如果查詢被編譯成并行查詢,但在運(yùn)行時(shí)作為串行查詢運(yùn)行,則由 SET STATISTICS XML 或通過(guò)使用 SQL Server Management Studio 中的“包括實(shí)際的執(zhí)行計(jì)劃”選項(xiàng)生成的顯示計(jì)劃輸出將不包含Parallelism運(yùn)算符的RunTimeInformation元素。在 SET STATISTICS PROFILE 輸出中,為Parallelism運(yùn)算符顯示的實(shí)際行計(jì)數(shù)和實(shí)際執(zhí)行數(shù)將為零。出現(xiàn)任何一種情況時(shí),都說(shuō)明Parallelism運(yùn)算符只在編譯查詢時(shí)使用,未在運(yùn)行時(shí)查詢計(jì)劃中使用。請(qǐng)注意,如果服務(wù)器上的并發(fā)負(fù)荷很高,則并行查詢計(jì)劃有時(shí)會(huì)以串行方式運(yùn)行。

Parameter Table Scan

Parameter Table Scan運(yùn)算符掃描在當(dāng)前查詢中用作參數(shù)的表。該運(yùn)算符一般用于存儲(chǔ)過(guò)程內(nèi)的 INSERT 查詢。Parameter Table Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

無(wú)

Partial Aggregate

Partial Aggregate用于并行計(jì)劃中。它將聚合功能應(yīng)用到盡可能多的輸入行中,以便不必執(zhí)行向磁盤寫入數(shù)據(jù)的操作(稱為“溢出”)。Hash Match是實(shí)現(xiàn)分區(qū)聚合的唯一一個(gè)物理運(yùn)算符(迭代器)。Partial Aggregate是一個(gè)邏輯運(yùn)算符。

Population Query

Population Query運(yùn)算符在打開(kāi)游標(biāo)時(shí)填充游標(biāo)的工作表。

Refresh Query

Refresh Query運(yùn)算符為提取緩沖區(qū)中的行提取當(dāng)前數(shù)據(jù)。

Remote Delete

Remote Delete運(yùn)算符用于從遠(yuǎn)程對(duì)象中刪除輸入行。Remote Delete既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Remote Index Scan

Remote Index Scan運(yùn)算符可以掃描在 Argument 列中指定的遠(yuǎn)程索引。Remote Index Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Remote Index Seek

Remote Index Seek運(yùn)算符利用遠(yuǎn)程索引對(duì)象的查找功能來(lái)檢索行。Argument列包含所使用的遠(yuǎn)程索引名稱和 SEEK:() 謂詞。Remote Index Seek是一個(gè)邏輯物理運(yùn)算符。

Remote Insert

Remote Insert運(yùn)算符將輸入行插入到遠(yuǎn)程對(duì)象。Remote Insert既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Remote Query

Remote Query運(yùn)算符將查詢提交給遠(yuǎn)程源。發(fā)送給遠(yuǎn)程服務(wù)器的查詢文本顯示在Argument列中。Remote Query既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Remote Scan

Remote Scan運(yùn)算符掃描遠(yuǎn)程對(duì)象。遠(yuǎn)程對(duì)象的名稱顯示在Argument列中。Remote Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Remote Update

Remote Update運(yùn)算符將更新遠(yuǎn)程對(duì)象中的輸入行。Remote Update既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Repartition Streams

Repartition Streams運(yùn)算符使用多個(gè)流并生成多個(gè)記錄流。記錄的內(nèi)容和格式不會(huì)改變。如果查詢優(yōu)化器使用位圖篩選器,則輸出流中行的數(shù)量將減少。輸入流中的每個(gè)記錄都放入一個(gè)輸出流中。如果該運(yùn)算符保留次序,則必須對(duì)所有輸入流排序并將它們合并到幾個(gè)有序的輸出流中。如果將輸出分區(qū),那么Argument列會(huì)包含 PARTITION COLUMNS:() 謂詞和分區(qū)列。如果輸出已經(jīng)排序,則Argument列包含一個(gè) ORDER BY:() 謂詞和已經(jīng)排序的列。Repartition Streams是一個(gè)邏輯運(yùn)算符。該運(yùn)算符只用于并行查詢計(jì)劃中。

Result

Result運(yùn)算符是查詢計(jì)劃結(jié)束時(shí)返回的數(shù)據(jù)。它通常是顯示計(jì)劃的根元素。Result是一個(gè)語(yǔ)言元素。

RID Lookup

RID Lookup是使用提供的行標(biāo)識(shí)符 (RID) 在堆上進(jìn)行的書(shū)簽查找。Argument列包含用于查找表中的行的書(shū)簽標(biāo)簽和從中查找行的表的名稱。RID Lookup通常帶有 NESTED LOOP JOIN。RID Lookup是一個(gè)物理運(yùn)算符。有關(guān)書(shū)簽查找的詳細(xì)信息,請(qǐng)參閱 MSDN SQL Server 博客中的Bookmark Lookup(書(shū)簽查找)。

無(wú)

Right Anti Semi Join

Right Anti Semi Join運(yùn)算符輸出第二個(gè)(底端)輸入中與第一個(gè)(頂端)輸入中的任何行都不匹配的每一行。匹配行的定義是滿足Argument列內(nèi)的謂詞的行(如果不存在謂詞,則每行都是一個(gè)匹配行)。Right Anti Semi Join是一個(gè)邏輯運(yùn)算符。

無(wú)

Right Outer Join

Right Outer Join運(yùn)算符返回滿足第二個(gè)(底端)輸入與第一個(gè)(頂端)輸入的每個(gè)匹配行的聯(lián)接的每行。此外,它還返回第二個(gè)輸入中在第一個(gè)輸入中沒(méi)有匹配行的任何行,即與 NULL 聯(lián)接。如果Argument列內(nèi)不存在任何聯(lián)接謂詞,則每行都是一個(gè)匹配行。Right Outer Join是一個(gè)邏輯運(yùn)算符。

無(wú)

Right Semi Join

第一個(gè)(頂端)輸入有匹配行時(shí),Right Semi Join運(yùn)算符返回第二個(gè)(底端)輸入中的每一行。如果Argument列內(nèi)不存在任何聯(lián)接謂詞,則每行都是一個(gè)匹配行。Right Semi Join是一個(gè)邏輯運(yùn)算符。

Row Count Spool

Row Count Spool運(yùn)算符掃描輸入,計(jì)算現(xiàn)有的行數(shù)并返回相同數(shù)目的不包含任何數(shù)據(jù)的行。必須檢查現(xiàn)有行數(shù)(而非行中包含的數(shù)據(jù))時(shí),使用此運(yùn)算符。例如,如果Nested Loops運(yùn)算符執(zhí)行左半聯(lián)接操作且聯(lián)接謂詞應(yīng)用于內(nèi)部輸入,則可以在Nested Loops運(yùn)算符內(nèi)部輸入的頂部放置行計(jì)數(shù)假脫機(jī)。這樣,Nested Loops運(yùn)算符就可以確定行計(jì)數(shù)假脫機(jī)輸出的行數(shù)(因?yàn)椴恍枰獌?nèi)側(cè)的實(shí)際數(shù)據(jù))以決定是否返回外部行。Row Count Spool是一個(gè)物理運(yùn)算符。

Segment

Segment既是一個(gè)物理運(yùn)算符,也是一個(gè)邏輯運(yùn)算符。它基于一個(gè)或多個(gè)列的值將輸入集劃分成多個(gè)段。這些列顯示為Segment運(yùn)算符中的參數(shù)。然后此運(yùn)算符每次輸出一個(gè)段。

無(wú)

Segment Repartition

在并行查詢計(jì)劃中,有時(shí)存在迭代器的概念性區(qū)域。此類區(qū)域中的所有迭代器都可通過(guò)并行線程執(zhí)行。這些區(qū)域本身必須串行執(zhí)行。單個(gè)區(qū)域內(nèi)的某些Parallelism迭代器稱為Branch Repartition。兩個(gè)這樣的區(qū)域邊界上的Parallelism迭代器稱為Segment RepartitionBranch RepartitionSegment Repartition是邏輯運(yùn)算符。

Sequence

Sequence運(yùn)算符驅(qū)動(dòng)大范圍的更新計(jì)劃。就其功能而言,該運(yùn)算符按順序(從上到下)執(zhí)行每個(gè)輸入。每個(gè)輸入通常是不同對(duì)象的更新。該運(yùn)算符只返回其上一個(gè)(底端)輸入中的行。Sequence既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Sequence Project

Sequence Project運(yùn)算符將添加列以便計(jì)算有序集。它基于一個(gè)或多個(gè)列的值將輸入集劃分成多個(gè)段。然后此運(yùn)算符每次輸出一個(gè)段。這些列在Sequence Project運(yùn)算符中作為參數(shù)顯示。Sequence Project既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Snapshot

Snapshot運(yùn)算符創(chuàng)建一個(gè)看不到其他人所做更改的游標(biāo)。

Sort

Sort運(yùn)算符可對(duì)所有傳入的行進(jìn)行排序。Argument列包含 DISTINCT ORDER BY:() 謂詞(如果此操作刪除了重復(fù)項(xiàng)),或 ORDER BY:() 謂詞(如果對(duì)逗號(hào)分隔的列列表進(jìn)行排序)。如果按升序?qū)α信判颍瑒t使用值 ASC 作為列的前綴;如果按降序?qū)α信判颍瑒t使用值 DESC 作為列的前綴。Sort既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Split

Split運(yùn)算符用于優(yōu)化更新處理。它將每個(gè)更新操作拆分成刪除和插入操作。Split既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Spool

Spool運(yùn)算符將中間查詢結(jié)果保存到tempdb數(shù)據(jù)庫(kù)中。

Stream Aggregate

Stream Aggregate運(yùn)算符按一列或多列對(duì)行分組,然后計(jì)算由查詢返回的一個(gè)或多個(gè)聚合表達(dá)式。此運(yùn)算符的輸出可供查詢中的后續(xù)運(yùn)算符引用和/或返回到客戶端。Stream Aggregate運(yùn)算符要求輸入在組中按列進(jìn)行排序。如果由于前面的Sort運(yùn)算符或已排序的索引查找或掃描導(dǎo)致數(shù)據(jù)尚未排序,則優(yōu)化器將在此運(yùn)算符前面使用一個(gè)Sort運(yùn)算符。在 SHOWPLAN_ALL 語(yǔ)句或 SQL Server Management Studio 的圖形執(zhí)行計(jì)劃中,GROUP BY 謂詞中的列會(huì)列在Argument列中,而聚合表達(dá)式列在Defined Values列中。Stream Aggregate是一個(gè)物理運(yùn)算符。

Switch

Switch是一種特殊類型的串聯(lián)迭代器,它具有n個(gè)輸入。有一個(gè)表達(dá)式與每個(gè)Switch運(yùn)算符關(guān)聯(lián)。根據(jù)表達(dá)式的返回值(在 0 到n-1 之間),Switch將適當(dāng)?shù)妮斎肓鲝?fù)制到輸出流。Switch的一種用途是與某些運(yùn)算符(如TOP運(yùn)算符)一起實(shí)現(xiàn)涉及快進(jìn)游標(biāo)的查詢計(jì)劃。Switch既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Table Delete

Table Delete物理運(yùn)算符刪除查詢執(zhí)行計(jì)劃的Argument列中所指定表中的行。

Table Insert

Table Insert運(yùn)算符將輸入的行插入到在查詢執(zhí)行計(jì)劃的Argument列指定的表中。Argument列還包含一個(gè) SET:() 謂詞,用于指示為每一列設(shè)置的值。如果Table Insert的插入值沒(méi)有子項(xiàng),插入的行則來(lái)自 Insert 運(yùn)算符本身。Table Insert是一個(gè)物理運(yùn)算符。

Table Merge

Table Merge運(yùn)算符可將合并數(shù)據(jù)流應(yīng)用到堆。該運(yùn)算符可在其Argument列中所指定的表中刪除、更新或插入行。執(zhí)行的實(shí)際操作取決于該運(yùn)算符的Argument列中指定的ACTION列的運(yùn)行時(shí)值。Table Merge是一個(gè)物理運(yùn)算符。

Table Scan

Table Scan運(yùn)算符從查詢執(zhí)行計(jì)劃的Argument列所指定的表中檢索所有行。如果 WHERE:() 謂詞出現(xiàn)在Argument列中,則僅返回滿足此謂詞的那些行。Table Scan既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Table Spool

Table Spool運(yùn)算符掃描輸入,并將各行的一個(gè)副本放入隱藏的假脫機(jī)表中,此表存儲(chǔ)在tempdb數(shù)據(jù)庫(kù)中并且僅在查詢的生存期內(nèi)存在。如果重繞該運(yùn)算符(例如通過(guò)Nested Loops運(yùn)算符重繞),但不需要任何重新綁定,則將使用假脫機(jī)數(shù)據(jù),而不用重新掃描輸入。Table Spool是一個(gè)物理運(yùn)算符。

Table Update

Table Update物理運(yùn)算符更新查詢執(zhí)行計(jì)劃的Argument列中所指定表中的輸入行。SET:() 謂詞確定每個(gè)更新列的值。可以在 SET 子句中、此運(yùn)算符內(nèi)的其他位置以及此查詢內(nèi)的其他位置引用這些值。

Table-valued Function

Table-valued Function運(yùn)算符計(jì)算表值函數(shù)(Transact-SQL 或 CLR)并將結(jié)果行存儲(chǔ)在tempdb數(shù)據(jù)庫(kù)中。當(dāng)父迭代器請(qǐng)求這些行時(shí),Table-valued Function將返回tempdb中的行。

調(diào)用表值函數(shù)的查詢生成具有Table-valued Function迭代器的查詢計(jì)劃。可以使用不同的參數(shù)值計(jì)算Table-valued Function

Table-valued Function XML Reader輸入 XML BLOB 作為參數(shù),并生成一個(gè)按 XML 文檔順序表示 XML 節(jié)點(diǎn)的行集。其他輸入?yún)?shù)可能會(huì)將返回的 XML 節(jié)點(diǎn)限于 XML 文檔的子集。

Table Valued Function XML Reader with XPath filter是一種特殊的XML Reader Table-valued Function,它將輸出限于滿足 XPath 表達(dá)式的 XML 節(jié)點(diǎn)。

Table-valued Function既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

Top

Top運(yùn)算符掃描輸入,但僅基于排序順序返回最前面的指定行數(shù)或行百分比。Argument列可以包含要檢查重復(fù)值的列的列表。在更新計(jì)劃中,Top運(yùn)算符用于強(qiáng)制實(shí)施行計(jì)數(shù)限制。Top既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。Top既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

無(wú)

Top N Sort

Top N SortSort迭代器類似,差別僅在于前者需要前N行,而不是整個(gè)結(jié)果集。如果N的值較小,SQL Server 查詢執(zhí)行引擎將嘗試在內(nèi)存中執(zhí)行整個(gè)排序操作。如果N的值較大,查詢執(zhí)行引擎將使用更通用的排序方法(該方法不采用N作為參數(shù))重新排序。

UDX

擴(kuò)展運(yùn)算符 (UDX) 可以實(shí)現(xiàn) SQL Server 中的一種 XQuery 或 XPath 操作。所有 UDX 運(yùn)算符既是邏輯運(yùn)算符,又是物理運(yùn)算符。

擴(kuò)展運(yùn)算符 (UDX)FOR XML用于將其輸入的關(guān)系行集序列化為 XML 表示形式,并以單個(gè)輸出行、單個(gè) BLOB 列的形式存儲(chǔ)。它是區(qū)分順序的 XML 聚合運(yùn)算符。

擴(kuò)展運(yùn)算符 (UDX)XML SERIALIZER是區(qū)分順序的一種 XML 聚合運(yùn)算符。它以 XML 文檔順序輸入表示 XML 節(jié)點(diǎn)或 XQuery 標(biāo)量的行,并在單個(gè)輸出行、單個(gè) XML 列中生成序列化的 XML BLOB。

擴(kuò)展運(yùn)算符 (UDX)XML FRAGMENT SERIALIZER是一種特殊類型的XML SERIALIZER,用于處理表示在 XQuery 插入數(shù)據(jù)修改擴(kuò)展中插入的 XML 片斷的輸入行。

擴(kuò)展運(yùn)算符 (UDX)XQUERY STRING計(jì)算表示 XML 節(jié)點(diǎn)的輸入行的 XQuery 字符串值。它是一個(gè)區(qū)分順序的字符串聚合運(yùn)算符。它輸出一行多列,表示包含輸入字符串值的 XQuery 標(biāo)量。

擴(kuò)展運(yùn)算符 (UDX)XQUERY LIST DECOMPOSER是一個(gè) XQuery 列表分解運(yùn)算符。對(duì)于表示 XML 節(jié)點(diǎn)的每個(gè)輸入行,它至少生成表示 XQuery 標(biāo)量的一個(gè)行,如果輸入的是 XSD 列表類型的行,則每個(gè)行都包含一個(gè)列表元素值。

擴(kuò)展運(yùn)算符 (UDX)XQUERY DATA在表示 XML 節(jié)點(diǎn)的輸入行上計(jì)算 XQuery fn:data() 函數(shù)的值。它是一個(gè)區(qū)分順序的字符串聚合運(yùn)算符。它輸出一行多列,表示包含fn:data()結(jié)果的 XQuery 標(biāo)量。

擴(kuò)展運(yùn)算符XQUERY CONTAINS在表示 XML 節(jié)點(diǎn)的輸入行上計(jì)算 XQuery fn:contains() 函數(shù)的值。它是一個(gè)區(qū)分順序的字符串聚合運(yùn)算符。它輸出一行多列,表示包含fn:contains()結(jié)果的 XQuery 標(biāo)量。

擴(kuò)展運(yùn)算符UPDATE XML NODE更新 XML 類型的modify()方法中 XQuery 替換數(shù)據(jù)修改擴(kuò)展的 XML 節(jié)點(diǎn)。

無(wú)

Union

Union運(yùn)算符掃描多個(gè)輸入,輸出掃描的每一行并刪除重復(fù)項(xiàng)。Union是一個(gè)邏輯運(yùn)算符。

Update

Update運(yùn)算符更新在查詢執(zhí)行計(jì)劃的Argument列中所指定對(duì)象中的每一輸入行。Update是一個(gè)邏輯運(yùn)算符。物理運(yùn)算符為Table Update、Index Update或Clustered Index Update。

While

While運(yùn)算符實(shí)現(xiàn) Transact-SQL while 循環(huán)。While是一個(gè)語(yǔ)言元素。

Window Spool

Window Spool運(yùn)算符將每個(gè)行擴(kuò)展為表示與行關(guān)聯(lián)的窗口的行集。在查詢中,OVER 子句定義查詢結(jié)果集內(nèi)的窗口和窗口函數(shù),然后計(jì)算窗口中的每個(gè)行的值。Window Spool既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

https://msdn.microsoft.com/zh-cn/library/ms187840%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396

Merge Interval 運(yùn)算符可合并多個(gè)(可能重疊的)間隔以得出最小的不重疊間隔,然后將其用于查找索引項(xiàng)。此運(yùn)算符通常出現(xiàn)在 Constant Scan 運(yùn)算符中的一個(gè)或多個(gè) Compute Scalar 運(yùn)算符上方,Constant Scan 運(yùn)算符構(gòu)造了此運(yùn)算符所合并的間隔(表示為一行中的多個(gè)列)。

Merge Interval 既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

圖形執(zhí)行計(jì)劃圖標(biāo)

Sequence Project

Sequence Project運(yùn)算符將添加列以便計(jì)算有序集。它基于一個(gè)或多個(gè)列的值將輸入集劃分成多個(gè)段。然后此運(yùn)算符每次輸出一個(gè)段。這些列在Sequence Project運(yùn)算符中作為參數(shù)顯示。Sequence Project既是一個(gè)邏輯運(yùn)算符,也是一個(gè)物理運(yùn)算符。

關(guān)系運(yùn)算

投影 projection,投影運(yùn)算也是單目運(yùn)算,關(guān)系R上的投影是從R中選擇出若干屬性列,組成新的關(guān)系,即對(duì)關(guān)系在垂直方向進(jìn)行的運(yùn)算,從左到右按照指定的若干屬性以及順序取出相應(yīng)列,刪除重復(fù)元組

投影運(yùn)算是從列的角度進(jìn)行的運(yùn)算,這正是選取運(yùn)算和投影運(yùn)算的區(qū)別所在,選取運(yùn)算是從關(guān)系的水平方向向上進(jìn)行運(yùn)算,而投影運(yùn)算則是從關(guān)系的垂直方向上進(jìn)行的

數(shù)據(jù)庫(kù)原理及應(yīng)用教程 第3版 陳志泊主編

本文版權(quán)歸作者所有,未經(jīng)作者同意不得轉(zhuǎn)載。

總結(jié)

以上是生活随笔為你收集整理的SQLSERVER中的假脱机spool的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。