婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 和表值函數連接引發的性能問題分析

和表值函數連接引發的性能問題分析

熱門標簽:怎樣把地圖標注導入公司地址 廣州人工電銷機器人費用 洛陽外呼系統平臺 電銷機器人被曝光 寧波人工外呼系統有效果嗎 地圖標注一個圓圈怎么用 400外呼系統合法 真人語音電銷機器人 如何在地圖標注自己店鋪

表值函數

    SQL Server中提供了類似其他編程語言的函數,而函數的本質通常是一段代碼的封裝,并返回值。在SQL Server中,函數除了可以返回簡單的數據類型之外(Int、Varchar等),還可以返回一個集合,也就是返回一個表。
    而根據是否直接返回集合或是定義后再返回集合,表值函數又分為內聯用戶定義表值函數和用戶定義表值函數(下文統稱為表值函數,省去“用戶定義”四個字)。

內聯表值函數
    內聯表值函數和普通函數并無不同,唯一的區別是返回結果為集合(表),而不是簡單數據類型,一個簡單的內聯表值函數如代碼清單1所示(摘自MSDN)。

CREATE FUNCTION Sales.ufn_CustomerNamesInRegion
( @Region nvarchar(50) )
RETURNS table
AS
RETURN (
SELECT DISTINCT s.Name AS Store, a.City
FROM Sales.Store AS s
INNER JOIN Person.BusinessEntityAddress AS bea 
ON bea.BusinessEntityID = s.BusinessEntityID 
INNER JOIN Person.Address AS a 
ON a.AddressID = bea.AddressID
INNER JOIN Person.StateProvince AS sp 
ON sp.StateProvinceID = a.StateProvinceID
WHERE sp.Name = @Region
);
GO

代碼清單1.一個簡單的表值函數

用戶定義表值函數
而用戶定義表值函數,需要在函數開始時定義返回的表結構,然后可以寫任何代碼進行數據操作,插入到定義的表結構之后進行返回,一個稍微負責的用戶定義表值函數示例如代碼清單2所示(摘自MSDN)。

CREATE FUNCTION dbo.ufnGetContactInformation(@ContactID int) 
RETURNS @retContactInformation TABLE 
( 
-- Columns returned by the function 
ContactID int PRIMARY KEY NOT NULL, 
FirstName nvarchar(50) NULL, 
LastName nvarchar(50) NULL, 
JobTitle nvarchar(50) NULL, 
ContactType nvarchar(50) NULL 
) 
AS 
-- Returns the first name, last name, job title, and contact type for the specified contact. 
BEGIN 
DECLARE 
@FirstName nvarchar(50), 
@LastName nvarchar(50), 
@JobTitle nvarchar(50), 
@ContactType nvarchar(50); 
-- Get common contact information 
SELECT 
@ContactID = BusinessEntityID, 
@FirstName = FirstName, 
@LastName = LastName 
FROM Person.Person 
WHERE BusinessEntityID = @ContactID; 
-- Get contact job title 
SELECT @JobTitle = 
CASE 
-- Check for employee 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'EM') 
THEN (SELECT JobTitle 
FROM HumanResources.Employee AS e 
WHERE e.BusinessEntityID = @ContactID) 
-- Check for vendor 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'VC') 
THEN (SELECT ct.Name 
FROM Person.ContactType AS ct 
INNER JOIN Person.BusinessEntityContact AS bec 
ON bec.ContactTypeID = ct.ContactTypeID 
WHERE bec.PersonID = @ContactID) 
 
-- Check for store 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'SC') 
THEN (SELECT ct.Name 
FROM Person.ContactType AS ct 
INNER JOIN Person.BusinessEntityContact AS bec 
ON bec.ContactTypeID = ct.ContactTypeID 
WHERE bec.PersonID = @ContactID) 
ELSE NULL 
END; 
-- Get contact type 
SET @ContactType = 
CASE 
-- Check for employee 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'EM') 
THEN 'Employee' 
-- Check for vendor 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'VC') 
THEN 'Vendor Contact' 
-- Check for store 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'SC') 
THEN 'Store Contact' 
-- Check for individual consumer 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'IN') 
THEN 'Consumer' 
-- Check for general contact 
WHEN EXISTS(SELECT * FROM Person.Person AS p 
WHERE p.BusinessEntityID = @ContactID AND p.PersonType = 'GC') 
THEN 'General Contact' 
END; 
-- Return the information to the caller 
IF @ContactID IS NOT NULL 
BEGIN 
INSERT @retContactInformation 
SELECT @ContactID, @FirstName, @LastName, @JobTitle, @ContactType; 
END; 
RETURN; 
END; 
GO

代碼訂單2.表值函數

為什么要用表值函數
    看起來表值函數所做的事情和存儲過程并無不同,但實際上還是有所差別。是因為表值函數可以被用于寫入其他查詢,而存儲過程不行。此外,表值函數和Apply操作符聯合使用可以極大的簡化連接操作。

    如果存儲過程符合下述條件的其中一個,可以考慮重寫為表值函數。

•存儲過程邏輯非常簡單,僅僅是一個Select語句,不用視圖的原因僅僅是由于需要參數。
•存儲過程中沒有更新操作。
•存儲過程中沒有動態SQL。
•存儲過程中只返回一個結果集。
•存儲過程的主要目的是為了產生臨時結果集,并將結果集存入臨時表以供其他查詢調用。

用戶定義表值函數的問題

    表值函數與內聯表值函數不同,內聯表值函數在處理的過程中更像是一個視圖,這意味著在查詢優化階段,內聯表值函數可以參與查詢優化器的優化,比如將篩選條件(Where)推到代數樹的底部,這意味著可以先Where再Join,從而可以利用索引查找降低IO從而提升性能。
    讓我們來看一個簡單的例子。下面代碼示例是一個簡單的和表值函數做Join的例子:
    首先我們創建表值函數,分別為內聯表值函數方式和表值函數方式,如代碼清單3所示。

--創建表值行數 
CREATE FUNCTION tvf_multi_Test ( ) 
RETURNS @SaleDetail TABLE ( ProductId INT ) 
AS 
BEGIN 
INSERT INTO @SaleDetail 
SELECT ProductID 
FROM Sales.SalesOrderHeader soh 
INNER JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID 
RETURN 
END 
--創建內聯表值函數 
CREATE FUNCTION tvf_inline_Test ( ) 
RETURNS TABLE 
AS 
RETURN 
SELECT ProductID 
FROM Sales.SalesOrderHeader soh 
INNER JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID 

代碼清單3.創建兩種不同的函數

現在,我們使用相同的查詢,對這兩個表值函數進行Join,代碼如代碼清單4所示。

--表值函數做Join 
SELECT c.personid , 
Prod.Name , 
COUNT(*) 'numer of unit' 
FROM Person.BusinessEntityContact c 
INNER JOIN dbo.tvf_multi_Test() tst ON c.personid = tst.ProductId 
INNER JOIN Production.Product prod ON tst.ProductId = prod.ProductID 
GROUP BY c.personid , 
Prod.Name 
 
--內聯表值函數做Join 
SELECT c.personid , 
Prod.Name , 
COUNT(*) 'numer of unit' 
FROM Person.BusinessEntityContact c 
INNER JOIN dbo.tvf_inline_Test() tst ON c.personid = tst.ProductId 
INNER JOIN Production.Product prod ON tst.ProductId = prod.ProductID 
GROUP BY c.personid , 
Prod.Name

代碼清單4.表值函數和內聯表值函數做Join

執行的成本如圖1所示。

圖1.兩種方式的成本

從IO來看,很明顯是選擇了次優的執行計劃,BusinessEntityContact選擇了121317次查找,而不是一次掃描。而內聯表函數能夠正確知道掃描一次的成本遠低于一次查找。

那問題的根源是內聯表值函數,對于SQL Server來說,和視圖是一樣的,這意味著內聯表值函數可以參與到邏輯執行計劃的代數運算(或者是代數樹優化)中,這意味著內斂表可以進一步拆分(如圖1所示,第二個內聯表的查詢,執行計劃具體知道內斂表中是SalesOrderHeader表和SalesOrderDetail表,由于查詢只選擇了一列,所以執行計劃優化直到可以無需掃描SalesOrderHeader表),對于內聯表值函數來說,執行計劃可以完整知道所涉及的表上的索引以及相關統計信息等元數據。
另一方面,表值函數,如圖1的第一部分所示,表值函數對整個執行計劃來說是一個黑箱子,既不知道統計信息,也沒有索引。執行計劃中不知道表值函數所涉及的表(圖1中為#AE4E5168這個臨時表,而不是具體的表明),因此對整個執行計劃來說該結果集SQL Server會假設返回的結果非常小,當表值函數返回的結果較多時(如本例所示),則會產生比較差的執行計劃。
因此綜上所述,在表值函數返回結果極小時,對性能可能沒有影響,但返回結果如果略多,則一定會影響執行計劃的質量。

如何處理
首先,在SQL Server中,我們要找出現存的和表值函數做Join的語句,通過挖掘執行計劃,我們可以找出該類語句,使用的代碼如代碼清單5所示。

WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) 
SELECT st.text, 
qp.query_plan 
FROM ( 
SELECT TOP 50 * 
FROM sys.dm_exec_query_stats 
ORDER BY total_worker_time DESC 
) AS qs 
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st 
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp 
WHERE qp.query_plan.exist('//p:RelOp[contains(@LogicalOp, "Join")]/*/p:RelOp[(@LogicalOp[.="Table-valued function"])]') = 1

代碼清單5.從執行計劃緩存中找出和表值函數做Join的查詢

結果如圖2所示。

圖2.執行計劃緩存中已經存在的和表值函數做Join的查詢

小結
本文闡述了表值函數的概念,表值函數為何會影響性能以及在執行計劃緩存中找出和表值函數做Join的查詢。對于和表值函數做Apply或表值函數返回的行數非常小的查詢,或許并不影響。但對于返回結果較多的表值函數做Join,則可能產生性能問題,因此如果有可能,把表值函數重寫為內聯表值函數或將表值函數的結果存入臨時表再進行Join可提升性能。

參考資料:

http://www.brentozar.com/blitzcache/tvf-join/

http://blogs.msdn.com/b/psssql/archive/2010/10/28/query-performance-and-multi-statement-table-valued-functions.aspx?CommentPosted=true#commentmessage

標簽:晉中 珠海 北海 煙臺 東營 南昌 石家莊 咸寧

巨人網絡通訊聲明:本文標題《和表值函數連接引發的性能問題分析》,本文關鍵詞  和,表值,函數,連接,引發,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《和表值函數連接引發的性能問題分析》相關的同類信息!
  • 本頁收集關于和表值函數連接引發的性能問題分析的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    久久电影网站中文字幕| 欧美精品1区2区| 免费在线观看精品| 国产露脸91国语对白| eeuss鲁片一区二区三区在线看| 国产一区二区调教| 99久久亚洲一区二区三区青草| 91久久精品午夜一区二区| 日韩欧美自拍偷拍| 久久一日本道色综合| 亚洲人亚洲人成电影网站色| 亚洲不卡av一区二区三区| 国产精品午夜在线| 亚洲成人免费在线观看| 国产九色sp调教91| 欧美日韩一区国产| 91精品欧美一区二区三区综合在 | 亚洲一区二区三区四区不卡| 亚洲在线观看免费| 激情小说欧美图片| 欧美性欧美巨大黑白大战| 中文在线免费一区三区高中清不卡| 偷偷要91色婷婷| 91麻豆国产在线观看| 国产欧美日韩久久| xfplay精品久久| 图片区小说区国产精品视频| bt欧美亚洲午夜电影天堂| 日韩精品一区二区三区在线观看| 亚洲色欲色欲www在线观看| 久久国产综合精品| 91福利精品第一导航| 日本亚洲三级在线| 国产精品污网站| 国产欧美精品一区二区三区四区| 欧美理论片在线| 亚洲资源中文字幕| 亚洲国产wwwccc36天堂| 欧美一区二区成人6969| 中文av一区特黄| 国产精品国产三级国产aⅴ中文| 亚洲一区二区免费视频| 欧美日本在线播放| 成人美女视频在线观看| 一本到不卡免费一区二区| 天天av天天翘天天综合网| 日韩欧美成人一区二区| 在线观看免费视频综合| 一本大道av伊人久久综合| 欧美影院精品一区| 91精品国产一区二区| 中文字幕亚洲欧美在线不卡| 日韩精品福利网| 色婷婷av一区二区| 成人欧美一区二区三区在线播放| 成人伦理片在线| 国产日韩精品视频一区| 日韩丝袜情趣美女图片| 亚洲国产成人av| 亚洲成人资源在线| 日韩精品91亚洲二区在线观看| 欧美国产日韩精品免费观看| 国产亚洲人成网站| 欧美色倩网站大全免费| 紧缚捆绑精品一区二区| 欧美日韩亚洲综合在线| 亚洲一二三四区不卡| 粉嫩aⅴ一区二区三区四区| 欧美一级理论性理论a| 99久久久久久99| 亚洲v中文字幕| 成人天堂资源www在线| 久久精品网站免费观看| 日韩一区二区电影| 91精品免费在线观看| 成人97人人超碰人人99| 日韩精品每日更新| 亚洲欧美日韩精品久久久久| 国产欧美一区二区精品性色| 99re视频这里只有精品| 极品美女销魂一区二区三区| 成人欧美一区二区三区黑人麻豆| 久久色在线视频| 国产精品久久久久久户外露出| 亚洲三级免费观看| 亚洲国产成人av好男人在线观看| 亚洲欧洲综合另类| 一区二区欧美精品| 亚洲天堂福利av| 欧美人体做爰大胆视频| 欧美精品一区二区在线播放| 91免费国产视频网站| 韩国理伦片一区二区三区在线播放| 成人av电影观看| 欧美一区二区视频免费观看| 91麻豆精品91久久久久久清纯| 91黄视频在线观看| 在线观看不卡视频| 欧美精品 国产精品| 欧美一区二区在线视频| 中文字幕精品—区二区四季| 亚洲综合丁香婷婷六月香| 午夜电影网一区| 久久99久久精品| 色婷婷激情久久| 日韩精品一区二区在线| 亚洲精品视频免费看| 国产一区二区三区在线观看免费 | 久久久久国产精品人| 亚洲蜜臀av乱码久久精品| 麻豆国产一区二区| 国产精品18久久久久久久久| 欧美日韩国产系列| 国产色婷婷亚洲99精品小说| 亚洲一区二区在线免费看| 国产精品一区三区| 欧美亚洲免费在线一区| 欧美激情在线一区二区| 日韩综合一区二区| 欧美伊人久久大香线蕉综合69| 国产欧美一区二区精品婷婷| 欧美aaaaaa午夜精品| 在线观看亚洲精品| 亚洲天堂精品视频| eeuss影院一区二区三区| 精品福利av导航| 三级亚洲高清视频| 欧美日韩综合在线免费观看| 成人免费一区二区三区在线观看| 国产精品综合二区| 久久综合九色综合久久久精品综合| 亚洲国产wwwccc36天堂| 欧美无人高清视频在线观看| 亚洲精品视频一区| 91官网在线观看| 一区二区在线观看av| 91老师国产黑色丝袜在线| 亚洲欧美在线视频| 91在线云播放| 一区二区三区在线视频观看 | 精品一二三四区| 欧美日韩国产综合久久| 亚洲国产视频网站| 欧美日韩国产电影| 日本va欧美va瓶| 欧美v国产在线一区二区三区| 久久成人免费网| 欧美激情在线免费观看| 不卡一二三区首页| 亚洲一区二区在线视频| 欧美一区2区视频在线观看| 蜜臀av性久久久久蜜臀aⅴ| 日韩一区二区三区电影在线观看 | 欧美经典一区二区三区| 国产99久久久国产精品潘金网站| 国产精品区一区二区三| av不卡免费在线观看| 一区二区三区在线看| 91精品国产综合久久精品麻豆| 久久不见久久见免费视频1| 久久综合九色综合欧美亚洲| 成人高清在线视频| 亚洲v中文字幕| 久久亚区不卡日本| 色婷婷av一区二区三区软件 | 狠狠色狠狠色综合系列| 欧美激情一区二区三区全黄| 在线亚洲+欧美+日本专区| 美腿丝袜亚洲色图| 国产精品拍天天在线| 欧美日韩一区二区在线观看| 国产最新精品免费| 亚洲欧美日韩人成在线播放| 日韩一区二区视频在线观看| 成人av网址在线| 日本一区中文字幕| 国产精品视频麻豆| 91精品国产综合久久精品图片| 成人精品视频一区二区三区| 视频一区国产视频| 中文字幕人成不卡一区| 91精品午夜视频| 91蜜桃视频在线| 国产麻豆视频一区二区| 日韩经典中文字幕一区| 国产精品不卡一区| 日韩精品一区二区三区在线播放 | 一区二区三区在线视频播放| 精品国产乱码久久久久久夜甘婷婷| 色呦呦国产精品| 成人午夜碰碰视频| 国产一区二区主播在线| 天堂成人国产精品一区| 亚洲欧美日韩成人高清在线一区| 久久久久久**毛片大全| 6080亚洲精品一区二区| 91一区二区三区在线观看| 国产一区二区三区观看| 天天色综合天天| 亚洲综合久久久久|