1. 程式人生 > >【SQL進階】03.執行計劃之旅1

【SQL進階】03.執行計劃之旅1

聽到大牛們說執行計劃,總是很惶恐,是對知識的缺乏的惶恐,所以必須得學習執行計劃,以減少對這一塊知識的惶恐,下面是對執行計劃的第一講-理解執行計劃。

本系列【T-SQL】主要是針對T-SQL的總結。

 

一、為什麼需要執行計劃?

(1)幫助分析

當我們想要去分析SQL語句存在很慢時,需要有一個分析工具幫助我們分析SQL語句中哪些地方存在效能問題,而這個分析工具就是執行計劃,看懂執行計劃就能知道哪些地方有效能問題,然後結合自己已有的SQL知識分析為什麼這些地方有效能問題,進而嘗試提出解決方案,並測試自己的方案是否能提高效能,以及方案是否合理。

(2)獲取其他資訊

       a.哪些索引被用在查詢中

       b.資料是怎樣關聯起來的

       c.資料是怎樣檢索的

       d.為什麼SQL Server沒有使用這些索引

       e.SQL語句的執行順序

二、什麼是執行計劃?

SQL語句執行之前,需要有一個執行的方案,而這個方案是由查詢優化器(查詢分析器)產生的,並且是高效的、開銷最小的方案,這就是執行計劃。不知道查詢優化器的可以看我寫之前寫的一篇部落格:

三、如何顯示執行計劃?

執行計劃有三種格式:圖形化執行計劃,文字化執行計劃,XML格式的執行計劃。

(1)圖形化執行計劃

 

優點:可視性好。

a.估計的執行計劃

可以通過滑鼠點選圖示顯示估計的執行計劃或者通過快捷鍵Ctrl+L顯示估計執行計劃。預估執行計劃不會真正執行,只是預估出來的執行計劃。

b.實際的執行計劃

單擊實際的執行計劃圖標,該圖示處於選中狀態,然後執行SQL語句,將會顯示實際執行的執行計劃。

(2)文字化執行計劃

 

用獨立的行來代表每一個迭代器。使用豎線(符號“|”)來代表查詢樹中迭代器之間的父子關係。資料都是從子迭代器流向父迭代器。

優點:和圖形計劃比較,文字執行計劃更容易儲存、處理、搜尋和比較。

--顯示完整的預估執行計劃資訊
SET SHOWPLAN_TEXT ON
GO
--顯示預估執行計劃的有限資訊,可以用osql.exe等工具分析
SET SHOWPLAN_ALL ON
GO
--顯示完整的實際執行計劃資訊
SET STATISTICS PROFILE ON
GO

總結:

 

(3)XML執行計劃

優點:三種執行計劃中最詳細的。圖形執行計劃可以儲存為副檔名為.sqlplan的XML格式的計劃檔案,開啟此檔案將會以圖形化的執行計劃展示。

--顯示預估執行計劃
SET SHOWPLAN_XML ON
GO
--顯示實際計劃的XML格式資料
SET STATISTICS XML ON
GO

 總結

四、如何分析執行計劃?

下面分析三種情況的執行計劃:

1.堆表

2.聚集索引

3.非聚集索引

結構 掃描 查詢 書籤查詢
堆表 表掃描 沒有這種情況 RID 查詢
聚集索引 聚集索引掃描 聚集索引查詢 沒有這種情況
非聚集索引 如果用到了索引,則是索引掃描 索引查詢 Key 查詢

關於表掃描的那些事:

  • 沒有索引的表稱作堆表,查詢匹配行用的是表掃描。
  • 如果出現表掃描操作,則證明這個表上一定沒有聚集索引。

關於索引查詢的那些事:

假設[列1]上有一個單列索引,可以使用這個索引查詢下面這些謂詞:

  1.[列1] = 1.23

  2.[列1] > 1.23

  3.[列1] BETWEEN 1 AND 100

  4.[列1] LIKE 'abc%'

  5.[列1] IN (1,3,7,10)

  不能使用這個索引對下列這些謂詞進行查詢:

  1.ABS[列1] = 1

  2.[列1] + 10 > 12

  3.[列1] LIKE '%abc'

關於非聚集索引的那些事:

  1. 如果只有非聚集索引時,非聚集索引不包含查詢列時,則SQL查詢優化器選擇非聚集索引掃描。
  2. 只有非聚集索引時,非聚集索引不包含過濾條件列時,則選擇表掃描。
  3. 非聚集索引具有獨立於資料行的結構。 非聚集索引包含非聚集索引鍵值,並且每個鍵值項都有指向包含該鍵值的資料行的指標。
  4. 從非聚集索引中的索引行指向資料行的指標稱為行定位器。 行定位器的結構取決於資料頁是儲存在堆中還是聚集表中。 對於堆,行定位器是指向行的指標。 對於聚集表,行定位器是聚集索引鍵。
  5. 您可以向非聚集索引的葉級新增非鍵列(包含列)以跳過現有的索引鍵限制(900 位元組和 16 鍵列),並執行完整範圍內的索引查詢。

關於聚集索引的那些事:

1. 如果表上有聚集索引,則掃描稱作聚集索引掃描,查詢稱作聚集索引查詢;

2. 聚集索引掃描和表掃描的效能沒多大差異;

3.聚集索引根據資料行的鍵值在表或檢視中排序和儲存這些資料行。

4.索引定義中包含聚集索引列。

5.每個表只能有一個聚集索引,因為資料行本身只能按一個順序排序。

6.只有當表包含聚集索引時,表中的資料行才按排序順序儲存。 如果表具有聚集索引,則該表稱為聚集表。如果表沒有聚集索引,則其資料行儲存在一個稱為堆的無序結構中。

7.加了聚集索引不一定能提高效能,有些情況下,效能可能不如表掃描;

8.聚集索引就是表本身。表有多少行和多少列,聚集索引就有多少行和和多少列。

9.單表查詢中,過濾條件中有聚集索引列,且能用這個索引查詢過濾條件中的謂詞,則是聚集索引查詢,過濾條件中沒有聚集索引列則是聚集索引掃描。

(1)沒有索引的情況

建立myOrder表

USE [Test]
GO
 
CREATE TABLE [dbo].[myOrder](
	[id] [int] NOT NULL,
	[customer] [nvarchar](100) NOT NULL
) ON [PRIMARY]
 
GO

myOrder只有兩列id,customer,這兩列上面都沒有索引。

SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'

下面是執行計劃:

 

customer列上面沒有索引,SQL Server需要讀取myOrder表的每一行來判斷customer='ddd',如果結果為true,則返回此行。

查詢的示例圖如下,customer=ddd 存在三條記錄。

注意:

1.掃描及查詢是SQL Server用來從表和索引中讀取資料的迭代器;

2.掃描用來處理整個表或索引的全部分支;

3.查詢是在謂詞基礎上有效返回索引中一個或多個範圍中的行。

(2)有非聚集索引的情況

在id上建立非聚集索引

USE [Test]
GO
 
--刪除索引dbo.myOrder.ID_NON_INDEX
DROP INDEX dbo.myOrder.ID_NON_INDEX
 
CREATE NONCLUSTERED INDEX [ID_NON_INDEX] ON [dbo].[myOrder] 
(
	[id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

1.查詢條件的列上沒有非聚集索引,查詢列上沒有非聚集索引->表掃描

--id列上有索引,customer列上沒有索引,查詢條件中用的是customer='ddd'進行過濾。
--由於customer列上沒有索引,所以需要進行表掃描來找到符合customer='ddd'的行。
SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'

SELECT [customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'
  
SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'

 SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2 AND [customer] ='ddd'

SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2 AND [customer] ='ddd'

2.查詢條件的列上有非聚集索引,查詢列上沒有非聚集索引->表掃描

--id列上有索引,customer列上沒有索引,查詢條件中用的是id=2進行過濾。
--SELECT查詢需要返回customer列,由於customer列上沒有索引,且索引[ID_NON_INDEX]不包含customer列,
--即使用非聚集索引掃描找到了符合過濾條件id=2的索引分支,但是隻能在該索引分支上面拿到id列的值,因為該索引分支只包含了id列,其他列的值拿不到。
--所以還是需要進行表掃描來找到符合條件的行,然後獲取該行的customer列的值。
--這裡有個疑問:為什麼找到索引分支後,不能繼續找到對應的行,然後拿到這行的customer列??
SELECT [customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2

SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2

 

3.查詢條件的列上有非聚集索引,查詢列上有非聚集索引->索引查詢

--id列上有索引,customer列上沒有索引,查詢條件中用的是id=2進行過濾。
--SELECT查詢需要返回id列,使用非聚集索引掃描找到了符合過濾條件id=2的索引分支,在找到的索引分支上拿到id列的值。
SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2

 

3)有聚集索引的情況

1.查詢條件的列上沒有聚集索引->聚集索引掃描

--
--id列上有聚集索引,customer列上沒有索引,查詢條件中用的是customer='ddd'進行過濾。
--由於customer列上沒有索引,所以需要進行掃描來找到符合customer='ddd'的行。
--只要有聚集索引,則掃描就是聚集索引掃描。聚集索引和表掃描的效能基本上一樣。
SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'
  
SELECT [customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'
  
SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] = 'ddd'

  

2.查詢條件的列上有聚集索引->聚集索引查詢

--id列上有索引,customer列上沒有索引,查詢條件中用的是id=2進行過濾。
--用聚集索引查詢到了id=2的行,由於表中的行就是按照id列來排序的,所以找到了這一行,
--也就能找到這一行的所有列,所以能夠拿到customer列。所以是聚集索引掃描。
 SELECT [customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2
  
SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2
  
 SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2

  

3.查詢條件中,有一列有聚集索引,另一列沒有聚集索引->聚集索引查詢

--id列上有索引,customer列上沒有索引,查詢條件中用的是[id] = 2,[customer] ='ddd'進行過濾。
--當過濾條件中有一個可以根據聚集索引來查詢時,先用聚集索引來找到匹配的行([id] = 2),然後再在過濾出來的行中篩選處符合[customer] ='ddd'的行。
--所以是聚集索引查詢。
--疑問:為什麼第二步篩選操作在執行計劃圖中沒有體現??這個地方我想到的是拿到id=2的匹配行後,直接捨棄掉不符合條件[customer] ='ddd'的行,這個捨棄動作就沒有直接體現出來。
  SELECT [id]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2 AND [customer] ='ddd'
  
  SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [id] = 2 AND [customer] ='ddd'
  
  SELECT [id],[customer]
  FROM [Test].[dbo].[myOrder]
  WHERE [customer] ='3333' AND [id] = 2

  


作  者:
出  處:http://www.cnblogs.com/jackson0714/
關於作者:專注於微軟平臺的專案開發。如有問題或建議,請多多賜教!
版權宣告:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。
特此宣告:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:如果您覺得文章對您有幫助,可以點選文章右下角推薦一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!

相關推薦

SQL03.執行計劃1

聽到大牛們說執行計劃,總是很惶恐,是對知識的缺乏的惶恐,所以必須得學習執行計劃,以減少對這一塊知識的惶恐,下面是對執行計劃的第一講-理解執行計劃。 本系列【T-SQL】主要是針對T-SQL的總結。   一、為什麼需要執行計劃? (1)幫助分析 當我們想要去分析SQL語句存在很慢時,需要有一個

Android 圖片載入框架Glide

生活 cannot 簡單介紹 style codes 詳細 npr 濾鏡 ive 簡單介紹 在泰國舉行的谷歌開發人員論壇上,谷歌為我們介紹了一個名叫 Glid

T-SQL02.理解SQL查詢的底層原理

本系列【T-SQL】主要是針對T-SQL的總結。 一、SQL Server組成部分 1.關係引擎:主要作用是優化和執行查詢。 包含三大元件: (1)命令解析器:檢查語法和轉換查詢樹。 (2)查詢優化器:優化查詢。 (3)查詢執行器:負責執行查詢。 2.儲存引擎:管理所有資料及涉及的IO

Java執行緒池深入理解

Java併發程式設計:執行緒池的使用在前面的文章中,我們使用執行緒的時候就去建立一個執行緒,這樣實現起來非常簡便,但是就會有一個問題:如果併發的執行緒數量很多,並且每個執行緒都是執行一個時間很短的任務就結束了,這樣頻繁建立執行緒就會大大降低系統的效率,因為頻繁建立執行緒和銷燬執行緒需要時間。那

Android(3)Android圖像處理

progress chang etc geo xtend static ogr arch 取出 1. 概念 色調/色相:物體傳遞的顏色 飽和度:顏色的純度,從0(灰)到100%(飽和)來進行描寫敘述 亮度/明度:顏色的相對明暗程度 2. 調整圖像小Demo 創建一個

AndroidJunit單元測試環境搭建以及簡單有用

rar theme 選擇 http 技術分享 才幹 ack package family 單元測試的目的 首先。Junit單元測試要實現的功能,就是用來測試寫好的方法是否可以正確的運行,一般多用於對業務方法的測試。 單元測試的環境配置 1.在Andro

MySQLKeepalived1.4.0結合MySQL 5.7.19實現主備高可用

port 腳本 amp ado roo ins log openss net 1、基本環境 數據庫安裝及主備同步接上一篇文章:http://blog.51cto.com/13946719/2309514JDK 1.8_171MySQL 5.7.19CentOS 7.4Kee

JavaScript深入理解JavaScript中ES6的Promise的作用並實現一個自己的Promise

  1.Promise的基本使用 1 // 需求分析: 封裝一個方法用於讀取檔案路徑,返回檔案內容 2 3 const fs = require('fs'); 4 const path = require('path'); 5 6 7 /** 8 * 把一個回

Android 仿抖音系列翻頁上下滑切換視訊(四)

大家好,我們又見面了。這是這個系列的第四篇,在這篇文章之前,建議可以先看下之前系列的文章,為了節省篇幅,之前詳細說過的地方,這裡就不再詳細描述了,下面是目錄: 【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一) 【Android 進階】仿抖音系列之列表播放視訊

Android 仿抖音系列列表播放視訊(三)

在上一篇【Android 進階】仿抖音系列之列表播放視訊(二)中,我們實現列表播放視訊,這一篇我們來對其做些優化。 【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一) 【Android 進階】仿抖音系列之列表播放視訊(二) 【Android 進階】仿抖音

Android 仿抖音系列列表播放視訊(二)

上一篇中,我們實現了仿抖音上下翻頁切換視訊的效果,詳見【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一),這一篇,我們來實現抖音列表播放視訊。 【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一) 【Android 進階】仿抖音系列之列表播放視訊(二)

Android 仿抖音系列翻頁上下滑切換視訊(一)

最近公司在做個短視訊的專案,其中借鑑了很多抖音的設計,其中就有抖音的上下滑切換視訊。 【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一) 【Android 進階】仿抖音系列之列表播放視訊(二) 【Android 進階】仿抖音系列之列表播放視訊(三)

Android 仿抖音系列視訊預覽和錄製(五)

大家好,又見面了。在前幾篇中,我們通過2種方式實現了仿抖音的翻頁切換視訊,仿抖音列表播放視訊功能,這一篇,我們來說說視訊的錄製。 【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一) 【Android 進階】仿抖音系列之列表播放視訊(二) 【Android

面試React元件設計模式(一)

完整程式碼可檢視github,這裡擷取的程式碼不影響理解就行。 頁面效果可檢視gitPage 首先編寫一下我們的公共元件 單個商品元件(商品元件:展示價格、購買數量) goodsItem.js // 單個商品 import React from 'react'; const GoodsItem =

CSSbox-shadow 與 filter:drop-shadow 詳解及奇技淫巧

box-shadow 在前端的 CSS 編寫工作想必十分常見。但是 box-shadow 除去它的常規用法,其實還存在許多不為人知的奇技淫巧。 box-shadow 常規用法 說到 box-shadow ,首先想到的必然是它能夠生成陰影,所以稱之為 shaodow ,簡單看看它的語法:

RedisRedis哨兵機制

1、哨兵機制的簡介        有了主從複製的實現以後,如果想對主伺服器進行監控,那麼在redis2.6以後提供了一個"哨兵"的機制。顧名思義,哨兵的含義就是監控redis系統的執行狀態。可

Android 一鍵清理

一鍵清理流程圖 系統快取分析 Android 已安裝 app /data/data/packagename/cache 資料夾和 /sdcard/Android/data/packagename/cache 資料夾組成 原生設定(Settings

Android實現各種各樣的Tab切換效果

一、View  + ViewPager 使用ViewPager和View實現切換效果,效果如下: 主佈局介面: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

python自定義庫函式

在python使用過程中,在不同的專案裡,常常會出現頻繁地自定義同一個函式的情況。為了解決這個問題,我們可以選擇建立一個自定義的庫,並將其新增到系統路徑中 具體操作如下: 在任意位置新建一個專案my_libs,並在其中新建python檔案my_lib1和m

Mybatis-- mybatis架構

1.什麼是mybatis   MyBatis是一個優秀的持久層框架,它對jdbc的操作資料庫的過程進行封裝,使開發者只需要關注 SQL 本身,而 不需要花費精力去處理例如註冊驅動、建立connect