主頁 > 資料庫 > PostgreSQL執行計劃概述

PostgreSQL執行計劃概述

2020-09-10 06:42:43 資料庫

 

執行計劃個人理解是一個“點”,“線”,“面”的問題,關系資料庫中執行計劃是一個同質化的物件,串聯起來還是比較容易掌握的,對于一條復雜的sql,所謂的點就是其中單個表的訪問方式,線是表之間的連接\驅動順序,面就是表與表之間的具體連接演算法以及中間結果在記憶體緩沖區中的處理(類似于bitmap scan,中間結果集的buffer處理等等),這樣一來,一個sql就的執行計劃就可以逐步拆解開來,可以逐個基于細節來分析,Postgresql的執行計劃,整體上看跟MySQL或者sqlserver都是差不多的,但Postgresql對執行計劃在細節上的描述還是很粗糙的,就索引的訪問形式來說:MySQL中有index 遍歷索引/range 索引范圍查找/ref 非唯一索引查找資料/eq_ref 非唯一索引查找資料,以及回表的標記;sqlserver中也存在著scan和seek是兩個完全不同的概念,以及明顯的“回表”標記,在postgresql執行計劃中是無法直接體現出來的,全部稱之為index scan(index only scan),這一點說實話是比不上MySQL或者sqlserver的,后兩者對執行計劃的描述都很細化,

1 執行計劃中的“點”

1.1 順序掃描Seq Scan

順序掃描實際上就是全表掃描,沒有任何可用索引或者不適合走索引的情況下的一種查詢行為 seq scan的圖形化示例

1.2 索引掃描IndexScan

通過訪問索引獲得元組位置指標后再訪問表資料本身,index scan實際上是包含了通過索引鍵值查找,然后“回表”的程序,這個執行計劃或者字面上,都沒有體現出來,

index scan的圖形化示例

1.3 Index Only Scan

如果索引scan不需要回表的話,執行計劃如果表達這種邏輯?
對于 index scan,如果一個查詢不需要回表的場景,比如select c1 from table where c1 =100;查詢的列在索引中就可以直接得到,無需回到基表去得到其他欄位,這種執行計劃叫做Index Only Scan
相比index scan,index only scan就是去掉“回表”這個程序,僅在索引樹上就可以完成的查詢

1.4 位圖索引掃描Bitmap Index Scan

bitmap index scan的詳細介紹見這里:https://www.cnblogs.com/wy123/p/13376991.html
bitmap的圖形化示例,其中包含了兩部分,第一是bitmap的生成程序,第二是多個bitmap之間的與(或)操作后排序,然后回表的程序,

1.5 預期的index only scan沒有出現

由于Index Only Scan表示僅需要索引就可以找到所需要的資料,無需回表,那么同樣在無需回表的情況下,postgresql如何區分對索引樹(b+)樹的查找(真正的二分法查找)和掃描(掃描整顆B+樹)?這個是一個有意思的問題,這里刻意創建一個抑制索引使用的但是無需回表的查詢: select c2 from myschema.table_test where c2+1 = 1001;,
看看會發生什么,這也是筆者在一開始想不明白的一個問題,它竟然總的是走了一個全表掃描???

從postgresql 11版本測驗到最新的postgresql 12最新版,表中的資料里從十萬級測驗到千萬級,都是這么一個全表掃描的執行計劃,搜遍全網都沒有發現對這個問題合理的解釋,或許用postgresql的人都比較注意sql的規范性從而避免索引被抑制的寫法,但是為什么這里需要“回表”? 對于這個查詢,可以肯定的是,索引樹的大小(size)是肯定小于基表的堆結構的,即便是無法直接使用到索引,但是掃描整個索引樹的代價是遠遠小于整個基表的,最后還是從官方檔案中發現這個對這個問題的解釋,真相還是有點意外,
這兩個問題雖然不完全相同,但還是有一些類似的地方,看來postgresql一些優化措施還是有進步空間的,說白了,官方就是說優化器不夠智能,無法識別類似情況,只能做全表掃描來實作,理論上說是可以index only scan完成的操作,為什么會出現seq scan? 其實這個并不難理解,當where條件時c+1 = 1001的時候,因為c+1 并不是一個直接可用的索引欄位,優化器并不知道這個運算式經過計算后可以轉換成一個索引欄位,因此會走全表掃描,至此,postgresql中僅從索引就可以得到查詢結果的情況下,如何區分對索引樹的二分法查找和索引樹掃描?
除此之外,對于其他關系資料庫中的select count(1) from table陳述句的優化,往往可以在一個長度較小的欄位上建立一個索引,然后查詢就自動遍歷這個索引來獲取總行數的優化思路,
在Postgresql中是行不通的,類似查詢Postgresql中并不會掃描一個較小的二級索引來實作count計算,而依舊走的是一個全面掃描,
這一點查閱相關資料說是與Postgresql的MVCC,事物可見性映射有關,也就是說在統計表中總行數的時候還要判斷遍歷的行數是不是對當前行可見的,參考這里,個人覺得其實并沒有說清楚, 類似select count(1) from table;沒有任何where條件下,默認一直是走seq scan table 的,究竟如何與事物的可見性關聯起來的?
事務可見性以及MVCC,這一點還是比較有搞頭的,埋個坑先:
因為事務的可見性只在資料行中標記,對索引是不生效的,難道說通過二級索引回表找到的記錄,都要進行一次可見性判斷?
https://www.postgresql.org/docs/9.4/index-scanning.html
https://www.postgresql.org/docs/current/storage-vm.html

2 執行計劃中的“線

相對MySQL處理復雜sql能力相對較弱(被吐槽較多的子查詢,盡管MySQL一直在改進他的執行計劃演算法),不太適合相對復雜的sql查詢的場景(網傳淘寶禁止三張以上的表join),postgresql宣稱能夠處理復雜的sql查詢,其實都是其背后的演算法決定的,
相比MySQL執行計劃連接路徑的貪心演算法,其最大的問題在于只關心區域,而不關心整體,可能每一步都是最優解,但最終可能不是最優解的情況,
postgresql采用動態規劃演算法和遺傳演算法結合起來生成執行計劃,理論上說postgresql的執行計劃生成演算法是更加優秀的,
類似圖的最短路徑演算法,比如從1到5的最短路徑: 1,對于貪心演算法來說,會走1-》2=》3=》5的路徑,當前的每一步都是最優解,整體上看并不是最優解,
2,對于動態規劃演算法來說,會走1=》4=》3=》5的路徑,其代價明顯優于貪心演算法的結果,
貪心算的問題潛在的問題很明顯,最終的解很可能不是最優的,盡管MySQL在這方面一直在改進,
對于動態規劃演算法可以遍歷所有路徑來獲取一個最短路徑,這種演算法在節點數超過一定程度之后的時間復雜度會呈指數級增長,因此postgresql也會采用折中一些的遺傳演算法來實作(類似遺傳基因改良程序,逐漸退化掉不好的部分),
不管是貪心演算法,還是動態規劃演算法,遺傳演算法,其本身各有優缺點:
前者實作簡單,時間復雜度低,但存在非最優解的情況;后者盡管可以得到最優解,但是其時間復雜度要大于貪心演算法,
同時也不難理解,為什么MySQL發展至今中沒有執行計劃快取? 就是因為其在相對簡單的場景下,執行計劃的生成代價相對較小,因此考慮可以不快取執行計劃,可以臨時性編譯,貪心演算法同時也決定了MySQL不太適合處理相對復雜的sql查詢場景,其實這恰恰吻合了互聯網專案短平快的特點么,所以MySQL適合這一套,有點野路子的風格(話說mysql的出身就比較野路子,此處野路子是褒義詞), 而postgresql執行計劃的訪問路徑生成代價相對較高,對于復雜的sql查詢每次編譯代價相對較大,因此就保留了執行計劃快取從而達到可重用的目的(pg_prepared_statements),這是典型的學院派的風格(出身于書香門第,加州大學),

3 執行計劃中的“面”

3.1 join方式

這里的“面”是表與表之間的連接處理方式,其實就是經典的loop join,merge join,hash join這三種join方式,
postgresql中的三種join方式與其他資料庫的join在思路上并無二致,原理也很簡單,基本上都有各自適合的場景和前提條件,

3.1.1 loop join
適合處理兩個較小的結果集的場景,同時,盡管是較小的結果集,在有索引驅動的情況下loop join的效率也會相對較高,第二個圖例就代表著基于索引驅動的loop join

3.1.2 merge join
適合處理兩個有序結果集的場景,或者jion雙方本身存在一致的索引鍵
相比loop join只有outer表會前推,merge join在join的時候,outer和inner表同時有一個“前推”的程序,也就是說隨著join的進行,outer表的鍵對inner表的探測次數會越來越少,
要清楚,outer table和inner table的有序是merge join的因,而非果,

3.1.3,hash join
對于無索引且結果集較大的場景,屬于重量級的查詢處理,
其實平時不得見經常出現hash join,如果一個系統的查詢中經常出現hash join,也不見得是一件好事,在前面兩種足夠“輕量級”join方式處理不動時的一種選擇,
相比以上兩種join方式,hash join可能較為難理解一點:hash join簡單說分兩個階段,第一個階段是構建hash桶,對join雙方較小的一個表的連接鍵生成hash桶,第二個階段是對join的另外一張表的鍵值基于hash運算后進行探測,
為什么要這么做?其實還是跟“join條件上沒有索引有關”,相當于間接性地生成了一個hash索引,因此這種情況適合join雙方都變較大,且沒有索引的場景,
那么,為什么在重量級的join情況下為什么不加索引呢,所以上面也說了,經常看到hash join并不代表什么好現象,而是一種不得已的選擇,

并行查詢

并行查詢可以應用在絕大多數上述的點線面中
比如并行Seq Scan,并行Index Scan,并行join等等,其目的就是多個CPU協同作業,然后匯總的一種思路,這一點postgresql還是比較給力的,當然也不是并行執行緒數越多越好(max_parallel_workers),

強制查詢提示

查詢提示作為優化的debug作用,可以嘗試強制按照非默認的執行方式來對比,參考這里:https://blog.csdn.net/jackgo73/article/details/89711523

 

以上截圖這些有趣的圖片來自于:https://momjian.us/main/writings/pgsql/internalpics.pdf

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/1164.html

標籤:PostgreSQL

上一篇:PostgreSQL筆記

下一篇:PostgreSQL MVCC原理以及事務可見性對執行計劃的影響

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more