[轉載]T-SQL(MSSQL)語句查詢執行順序

来源:http://www.cnblogs.com/Scl891004X/archive/2016/12/02/6125229.html
-Advertisement-
Play Games

本篇博文,作為SQL查詢性能優化的基礎,只針對查詢流程深入剖析其來龍去脈。 ...


註意:筆者經過實驗和查閱資料,已在原作基礎上做了部分更改。更改不代表原作觀點,查看原作請點擊下方鏈接。

原文出處:

作者:張龍豪

鏈接:http://www.cnblogs.com/knowledgesea/p/4177830.html

前言

資料庫的查詢執行,毋庸置疑是程式員必備技能之一,然而資料庫查詢執行的過程絢爛多彩,卻是很少被人瞭解,今天哥哥要帶你裝逼帶你飛,深入一下這sql查詢的來龍去脈,為查詢的性能優化處理打個基礎,或許面試你也會遇到,預防不跪還是看看吧。

這篇博客,摒棄查詢優化性能,作為其基礎,只針對查詢流程講解剖析。

本片博客闡述的過程為

1、上一個標識過的sql語句,展示查詢執行的流程

2、上一個流程圖

3、做一個例子逐步深入分析,幫助理解

4、做一個裝逼的總結

sql查詢語句的處理步驟,代碼清單

 
--查詢組合欄位
select (6)distinct (8)top(<top_specification>)(5)<select_list>
--連表
(1)from (1-J)<left_table><join_type> join <right_table> on <on_predicate>
        (1-A)<left_table><apply_type> apply <right_table_expression> as <alias>
        (1-P)<left_table> pivot (<pivot_specification>) as <alias>
        (1-U)<left_table> unpivot (<unpivot_specification>) as <alias>
--查詢條件
(2)where <where_pridicate>
--分組
(3)group by <group_by_specification>
--分組條件
(4)having<having_predicate>
--排序
(7)order by<order_by_list>
 

說明:

1、順序為有1-8,8個大步驟,1-J,1-A,1-P,1-U,為並行次序。如果不夠明白,接下來我在來個流程圖看看。

2、執行過程中也會相應的產生多個虛擬表(下麵會有提到),以配合最終的正確查詢。

sql查詢語句的處理步驟,流程圖

 註:上述流程圖保留原作。經過實驗和查閱資料,做如下修改:計算表達式為第5步,distinct為第6步,order by為第7步,top為第8步,應在order by之後

實例準備,創建表,插入數據,寫要分析的實例查詢語句

1、首先創建兩個表

2、創建兩個表,並插入表數據,腳本如下 

USE [test]
GO
/****** Object:  Table [dbo].[Member]    Script Date: 2014/12/22 14:05:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Member](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](30) NULL,
    [phone] [varchar](15) NULL,
 CONSTRAINT [PK_MEMBER] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[Order]    Script Date: 2014/12/22 14:05:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Order](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [member_id] [int] NULL,
    [status] [int] NULL,
    [createTime] [datetime] NULL,
 CONSTRAINT [PK_ORDER] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[Member] ON 

GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (1, N'張龍豪', N'18501733702')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (2, N'Jim', N'15039512688')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (3, N'Tom', N'15139512854')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (4, N'Lulu', N'15687425583')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (5, N'Jick', N'13528567445')
GO
SET IDENTITY_INSERT [dbo].[Member] OFF
GO
SET IDENTITY_INSERT [dbo].[Order] ON 

GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (1, 1, 3, CAST(0x0000A40900B3BBFB AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (2, 2, 1, CAST(0x0000A40900B3CEF2 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (3, 3, 4, CAST(0x0000A40900B3D2D0 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (4, 4, 0, CAST(0x0000A40900B3D660 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (5, 5, 1, CAST(0x0000A40900B3D9B9 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (6, 6, 2, CAST(0x0000A40900B3DFEA AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (7, NULL, 0, CAST(0x0000A40900E34971 AS DateTime))
GO
SET IDENTITY_INSERT [dbo].[Order] OFF
GO
ALTER TABLE [dbo].[Order] ADD  DEFAULT (getdate()) FOR [createTime]
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'編號' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Member', @level2type=N'COLUMN',@level2name=N'id'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'姓名' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Member', @level2type=N'COLUMN',@level2name=N'Name'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'電話' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Member', @level2type=N'COLUMN',@level2name=N'phone'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'會員表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Member'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'編號' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Order', @level2type=N'COLUMN',@level2name=N'id'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'會員編號' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Order', @level2type=N'COLUMN',@level2name=N'member_id'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'訂單狀態' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Order', @level2type=N'COLUMN',@level2name=N'status'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'下單日期' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Order', @level2type=N'COLUMN',@level2name=N'createTime'
GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'訂單表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Order'
GO
View Code 

3、編寫咱們要解析的查詢語句,即本篇要查詢的實例語句。

 
select top(4)  status , max(m.id) as maxMemberID
from [dbo].[Member] as m right outer join [dbo].[Order] as o 
on m.id=o.member_id  where m.id>0
group by status 
having status>=0
order by maxMemberID asc
 

實例語句分步驟分析

第一步,從from開始。

1.1、載入左表

from [dbo].[Member] as m 

查詢結果:member表中的所有數據

1.2、這裡應該是 right outer join ,但是這裡在sql中被定義分解為2個步驟,即join ,right outer join 。表達式關鍵字從左到右,依次執行。

join [dbo].[Order] as o 

查詢結果:存入虛擬表vt1,為兩個表的笛卡爾集合。這裡你或許不明白什麼叫笛卡爾集合,我打個比方給說說,還望不要嫌棄,就是小朋友握手問題,A班裡有3個學生(看作一個表的三條數據),B班裡有2個學生(看作另外一個表的2條數據).B班小朋友跟A班小朋友搞聯歡晚會,首先要每個人都要確保跟另外一個班的同學我一下手,那麼交叉出來的集合就是(2*3=6)有6條不同的軌跡。這個軌跡的集合就是笛卡爾集合。如果你還不明白,我再說下,就是m(5條數據)表中的第一條數據跟o(7條數據)表中的所有數據握下手,有7條,然後依次類推共有35條不同的數據。這裡的null值也是要加進來的。

1.3、on 篩選器

on m.id=o.member_id 

查詢結果:從上一步的笛卡爾集合35條數據中刪除掉不匹配的行,就得到啦5條數據,存入虛擬表Vt2

1.4、添加外部行(outer row)

right outer join [dbo].[Order] as o 

查詢結果為:右表(order)作為保留表,把剩餘的數據重新添加到上一步的虛擬表中vt2,生成虛擬表vt3.

第二步,進入where階段

where m.id>0

查詢結果:存入虛擬表vt4,為篩選的條件為true的結果集,這裡加入一個記憶點,就是,where的篩選刪除為永久的,而on的篩選刪除為暫時的,因為on篩選過後,有可能會經過outer添加外部行,重新把數據載入回來,而where則不能。

第三步,group by分組

group by status

查詢結果:存入vt5,以status列的數值開始分組,即status列,值一樣的分為一組,這裡的兩個null在三值邏輯中被視為true。三值邏輯:true,false,null。此三值,null為未知,是數據的邏輯特色,有的地方兩個null相等為ture,在有些地方則為false。這個你百度下看看有很多講解。

第四步,having篩選器

having status>=0 

查詢結果:篩選分好組的組數據,把不滿足條件的刪除掉,存入虛擬表vt6

第五步,select查詢挑揀計算列

select status , max(m.id)

查詢結果:從分過組的數據中計算各個組中的最大m.id,列出要篩選顯示的列,產生vt7。

第六步,distinct過濾重覆

將重覆的行從vt7中刪除,產生vt8

第七步,order by 排序

將vt8中的行按ORDER BY子句中的列列表順序,生成一個游標(vc9)。

第八步,top篩選行,並返回給調用者。

從vc9的開始處選擇指定數量或比例的行,生成表vt10,並返回給調用者。

蛋疼的總結,裝逼是有依據的

本篇博客參考:《Microsoft SQL Server 2008技術內幕:T-SQL查詢》,感謝閱讀,(C#).NET技術分享QQ群: 232458226,歡迎加入。


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

-Advertisement-
Play Games
更多相關文章
  • flume配置: #DBFile DBFile.sources = sources1 DBFile.sinks = sinks1 DBFile.channels = channels1 # DBFile-DB-Source DBFile.sources.sources1.type = spooldi... ...
  • MYSQL保存BOOLEAN值時用1代表TRUE,0代表FALSE,boolean在MySQL里的類型為tinyint(1), MySQL里有四個常量:true,false,TRUE,FALSE,它們分別代表1,0,1,0, ...
  • 未分區的表,只能存儲在一個FileGroup中;對Table進行分區後,每一個分區都存儲在一個FileGroup,或分散式存儲在不同的FileGroup中。對錶進行分區的過程,是將邏輯上完整的一個表,按照特定的欄位拆分成多個分區,分散到(相同或不同的)FileGroup中,每一個部分叫做表的一個分區 ...
  • 1 概述 在集成項目中需要應對不同環境下的安裝配置,主流操作系統大致可以分為三種:Linux、Windows以及UNIX。其中Linux備受青睞的主要原因有兩個: 首先,Linux作為自由軟體有兩個特點:一是它免費提供源碼,二是愛好者可以按照自己的需要自由修改、複製和發佈程式的源碼,並公佈在Inte ...
  • 任務目標: 編譯安裝LAMP 要求(1) 安裝一個模塊化的PHP 要求(2) 安裝一個FPM的PHP 註意PHP需要最後一個安裝,因為需要前兩者的支持. 所以這裡的安裝次序為 1.httpd 2.MariaDB 3.PHP 一、安裝包組 # yum groupinstall "Development... ...
  • 本篇博文主要講解Oracle資料庫SQL語句完整的執行順序,文中也順便稍微提一下Oracle資料庫相關的知識。 ...
  • LifeCycleState: IDLE, START, STOP, ERROR [Source]: org.apache.flume.Source 繼承LifeCycleAware{stop() + start() + getLifeCycleState()} + NamedComponent{g ...
  • 這是mongodb裡面學習的關於性能的知識點,資料庫的管理無非就是維護和優化。維護在於平時的功能維護,其中優化就包括慢查詢和性能提高了。本次文章裡面提到從索引建立到監控,比較全面的闡述了在mongodb的優化中需要的過程。希望對自己日後的工作提供方便查閱,也希望對大家有用。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...