關於T-SQL重編譯那點事,內聯函數和表值函數在編譯生成執行計劃的區別

来源:http://www.cnblogs.com/wy123/archive/2017/01/10/6266724.html
-Advertisement-
Play Games

本文出處:http://www.cnblogs.com/wy123/p/6266724.html 最近在學習 WITH RECOMPILE和OPTION(RECOMPILE)在重編譯上的區別的時候,無意中發現表值函數和內聯表值函數編譯生成執行計劃的區別下文中將會對此問題展開討論。簡單地說就是:同樣一 ...


 

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

 

最近在學習 WITH RECOMPILE和OPTION(RECOMPILE)在重編譯上的區別的時候,無意中發現表值函數和內聯表值函數編譯生成執行計劃的區別
下文中將會對此問題展開討論。
簡單地說就是:同樣一句SQL,分別寫成內聯函數和表值函數,然後執行對Function的查詢,發現其執行計劃和執行計劃緩存是不一樣的,
根據某些測試的一些共同規律發現,內聯函數的編譯很有可能與Parameter Embedding Optimization 有關
關於Parameter Embedding Optimization,我在http://www.cnblogs.com/wy123/p/6262800.html寫了一個案例
在發生Parameter Embedding Optimization做編譯優化的時候,跟普通的編譯優化機制還是有很大差異的。

 

概念解釋:內聯用戶定義函數和表值用戶定義函數

  SQL Server中的表值函數分為“內聯用戶定義函數”和“表值用戶定義函數”。

 

內聯用戶定義函數(Inline User-Defined Functions):
  不上MDSN上搬概念了,簡單地說,內聯函數的特點就是就是返回類型為table,返回的結果是一個查詢語句
  如下,dbo.fn_InlineFunction即為內聯用戶定義函數,當然後面要與表值用戶定義函數作比較,就能看出來區別了

create function dbo.fn_InlineFunction
(
    @p_parameter     varchar(500)
)
returns table
as
return
(
    SELECT id,col2
    FROM [dbo].[TestTableValueFunction] 
    where ( col2  = @p_id or @p_id is null)      
)
GO

 

 

表值用戶定義函數(Table-Valued User-Defined Functions),
  與內聯函數區別在於,表值用戶定義函數返回的是一個表變數,在函數體中,通過賦值給這個表變數,然後返回表變數
  如下dbo.fn_TableValuedFunction即為內聯用戶定義函數,

create function fn_TableValuedFunction
(
    @p_paramter      varchar(500)
)
RETURNS @Result TABLE
(
    id int ,
    value char(5000)
)
as
begin
    
    insert into @Result
    select id,col2
    from [dbo].[TestTableValueFunction] 
    where ( col2  = @p_id or @p_id is null)   
      
    return
end

  熟悉sqlserver的同學可能已經知道這兩者的區別了,關於內聯用戶定義函數和表值用戶定義函數就先這麼簡單說一下區別
  雖然內聯函數和表值函數在功能上和使用上是有一些差異的,但是有一部分查詢,用兩種方式都可以實現,也就說兩者在功能上有差異也有交集。

 

開始本文主題

 

同樣的SQL語句,使用內聯函數和使用表值函數查詢生成執行計劃的區別

  按照慣例,先造一個測試表,char(500)的欄位可以是的表以及索引占用空間變大,後面對比測試的效果變得更加明顯。

create table TestTableValueFunction
(
    id int IDENTITY(1,1),
    col2 char(500)
)
GO

INSERT INTO TestTableValueFunction VALUES (NEWID())
GO 1000000

CREATE INDEX idx_col2 on TestTableValueFunction(col2)
GO

  同樣的查詢條件下,分別用內聯函數和表值函數查詢,查看其性能

  

  首先使用內聯函數的方式查詢,用插入數據中的一條值做查詢,最直觀的方式去看SSMS的執行時間,顯示為0秒,本機測試幾乎是瞬間就出來結果了
  可以看到執行計划走的是原始表TestTableValueFunction上idx_col2索引查找Index Seek

 

觀察IO,發現發生了8次IO

  使用表值函數的方式查詢,使用上面同樣的條件做查詢,SSMS顯式耗時4秒(本機測試的,可以忽略測試環境的外界影響因素)
  但是使用表值函數無法直接觀察查詢的執行計劃和IO信息,這兩個信息後面從計劃緩存中查詢

   

  其顯示的IO信息應該也不是原始的SQL的IO,應該是表變數的IO,原始SQL語句的IO和執行計劃信息暫時看不到,後面再說

   

 

為什麼同樣的查詢,使用表值函數,性能差異居然有這麼大?

  對於表值函數,由於無法直接觀察到其實際執行計劃和IO信息,那麼我們去查詢其緩存的執行計劃和IO信息
  如下,sys.dm_exec_query_stats系統表中查詢到其最近一次執行的IO信息,76997,遠遠大於上面的8次IO
  查看緩存的執行計劃

  

  從緩存中的執行計劃可以看到,其執行計劃為全表掃描

  

  到這裡就有意思了,既然是一樣的SQL,寫成內聯函數和表值函數,兩者的執行計劃不一樣,
  那麼就可以推斷出,SQL Server對內聯函數和表值函數的編譯處理方式是不一樣的。
  同時,上面的內聯函數是可以知道看到實際執行計劃的,顯示為Index Seek,
  但是在觀察緩存計劃的時候,是沒有查到的,如下截圖,也就是說內聯函數dbo.fn_InlineFunction對應的SQL的執行計劃是沒有被緩存起來的
  種種跡象不由的使我想到上一篇關於T-SQL重編譯那點事中,OPTION(RECOMPILE)的The Parameter Embedding Optimization編譯優化機制
  從內聯函數的SQL的執行計劃發現,編譯過程中是對SQL語句做植入參數優化+簡化,又因為沒有緩存執行計劃,那麼很有可能是發生了重編譯
  從個這兩點來看,跟OPTION(RECOMPILE)強制重編譯中的The Parameter Embedding Optimization編譯優化機制基本上是吻合的

  

  回頭再說表值函數為什麼是全表掃描?參考下圖,正常情況下這種查詢邏輯就是走的全表掃描
  只不過是內聯函數裡面,編譯優化機制對這種寫法做了專門的優化,才能走一個索引查找的方式。
  這也正是內聯函數和表值函數在編譯上最大的區別之一。
  對於為什麼表值函數裡面這種邏輯會在造成全表掃描在上一篇也解釋了,這裡就不啰嗦了。

如上,同樣的T-SQL查詢,在末尾加上OPTION(RECOMPILE),執行計劃也變成了Index Seek,跟內聯函數的執行計劃一致(都是index Seek),當然內聯函數中是沒有加OPTION(RECOMPILE)的

因此這裡有理由懷疑,內聯函數的編譯,是類似等價於加了OPTION(RECOMPILE)的

  之前只是瞭解過內聯函數和表值函數在預估方面的區別(不過記得好像是SQL Server2012之後對錶值函數的預估計算方式也做了更新),
   除此之外,從來沒有註意到也沒有考慮過兩者在編譯以及計劃緩存方面的區別
   工作中見到過有人使用內聯函數做複雜的查詢,並且是查詢條件是(col2 =@p_parameter or @p_parameter is null)這種方式
   如果是在存儲過程中,這種方式是會抑制到索引的使用的,之前“理所當然地”認為,寫成內聯函數,肯定也會抑制索引的使用
  不過從這個測試case來看,內聯函數這種寫法,確實可以正常使用索引

 

總結
  本文通過一個簡單的case,來演示了內聯函數和表值函數在編譯上的一些差別,優化器對內聯函數進行專門的優化處理,而不會去對錶值函數做特別的優化。
  在對內聯函數做特殊優化的時候,雖然沒有明確執行強制重編譯,但等效於存在類似於option(recompile)的基於sql語句級的強制重編譯優化機制。

 

 

   


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這個效果的完成主要分為兩個部分 1. 自定義view作為listview的列表項 一個view裡面包括 顯示頭像,名字,消息內容等的contentView和滑動才能顯示出來的刪除,置頂的右邊菜單menuView 在手指移動的時候同時改變這兩個視圖的位置 2. 重寫listview 判斷item向左還 ...
  • 概述 VS自2015把Xamarin集成進去後搞Android開發就爽了,不過這安裝VS2015完成的時候卻是長了不知道多少。廢話少說進正題,VS2015安裝時註意把Android相關的組件勾選安裝,別組件都沒安裝就來用VS搞Android開發。 VS2015的Android組件安裝完成後並不是什麼 ...
  • 數據稽核及處理技術方案 數據稽核及處理技術方案 編寫與審核人 編寫 審核 日期 備註 劉嘉勁、韋譽、溫智勇 陶心萬 2016-12-28 修改歷史 日期 版本 作者 修改內容 更改請求號 註釋:“更改請求號”為文檔正式發佈後需要變更時的編號。 編寫與審核人 編寫 審核 日期 備註 劉嘉勁、韋譽、溫智 ...
  • 一、數據備份(導出) 1、exp命令導出dmp文件(exp -help查看幫助信息) 命令:exp username/[email protected]/orcl file=C:\jds.dmp log=C:\jds.log tables=tablename...;(不寫tables ...
  • 前言 應用系統承載著大量的業務,隨之而來的是複雜的業務邏輯,在資料庫上的表現就是有著大量的不同種類的SQL語句。 SQL語句執行的快慢又與阻塞等待有著密不可分的原因。 系統慢可能有很多種原因,硬體資源不足,語句不優化,結構設計不合理,缺少必要的運維方式。所有的這些問題都可以在阻塞與等待中看出端倪,發 ...
  • Sqlserver 高併發和大數據存儲方案 隨著用戶的日益遞增,日活和峰值的暴漲,資料庫處理性能面臨著巨大的挑戰。下麵分享下對實際10萬+峰值的平臺的資料庫優化方案。與大家一起討論,互相學習提高! 案例:游戲平臺. 1、解決高併發 當客戶端連接數達到峰值的時候,服務端對連接的維護與處理這裡暫時不做討 ...
  • 今天使用SQLCMD導入到SQL SERVER資料庫中,看著數據文件都成功執行,但是意外發現有一個文件數據沒有成功導入,但執行不報錯,很容易導致問題被忽略。 使用存在問題的文件做下測試,從界面上看幾行腳本沒有任何問題: 4條INSERT語句“幾乎”一樣,區別在於最上面三行的部分文字是我從問題語句中粘 ...
  • 未來的BI市場是巨大的,涉及的觸角也會越來越多。就我觀察到的企業應用以及數據類產品中發現,很多企業通過數據介面引入了更多外部的數據來完善分析,也有部分企業私有化部署的BI產品在往雲BI方向發展。與R語言、數據挖掘類技術的集成,也將進一步提高數據分析的深度。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...