PostgreSQL與SQL Server:B樹索引差異及去重的優勢

PostgreSQL與SQL Server:B樹索引差異及去重的優勢

在優化查詢性能方面,索引是數據庫工程師可使用的最強大工具之一。PostgreSQL和Microsoft SQL Server(或Azure SQL)都將B樹索引用作其默認索引結構,但每個系統實現、維護和使用這些索引的方式存在細微卻重要的差異。

在這篇博文中,我們探討了PostgreSQL和SQL Server的幾個關鍵差異點:它們的B樹索引在底層的實現方式,以及它們在磁盤上存儲和訪問數據的方式。我們還將對每個數據庫系統中值的去重對索引大小的影響進行基準測試。

我們在文末還附上了一份全面的參考指南(參見Postgres與SQL Server索引對比表)。無論你是在優化查詢,還是在規劃遷移,這些差異都會對性能和索引策略產生顯著影響。

PostgreSQL與SQL Server中B樹索引的工作原理

從宏觀層面來看,這兩種數據庫都使用B樹索引來加快等值查詢和范圍查詢的速度。B樹保持有序狀態,并且經過平衡處理,以確保穩定的讀取性能。不過,盡管這兩種數據庫中B樹的概念相似,但其實現方式卻會對性能產生重要影響。

SQL Server 使用聚集索引通過索引列對表的數據進行物理排序。定義聚集索引后,表中的行將按照與索引本身相同的順序存儲。非聚集索引單獨存儲,并使用行定位符(RID 或聚集鍵)指向行。這種物理排序有利于范圍掃描或分頁查詢,但這也意味著每個表只能有一個聚集索引。更重要的是,SQL Server 會完整存儲每個索引項,即使同一頁上的多個項具有相同的值。由于沒有去重功能,因此包含許多重復值的索引可能會變得很大,并消耗過多的 I/O。

PostgreSQL沒有SQL Server意義上的聚集索引。所有PostgreSQL表都存儲為無序堆,而索引純粹是指向堆中元組的邏輯結構。這種設計為PostgreSQL提供了一定的靈活性:它使索引維護更簡單,并避免了物理重排的復雜性。

然而,這也意味著你不能依賴索引來定義表的物理布局。如果查詢性能取決于按特定順序讀取數據,Postgres確實允許你運行CLUSTER命令,但這需要完整的表鎖。在生產環境中,你可以使用pg_repack等工具來達到類似的效果。

因此,雖然這兩種數據庫都默認使用B樹索引,但SQL Server的索引與物理存儲之間的緊密耦合帶來了一系列不同的預期和限制。PostgreSQL的索引模型存在一些性能缺陷(因為它沒有聚簇索引的實現),但去重等獨特功能使其在其他情況下表現更佳。

PostgreSQL的B樹去重

PostgreSQL 13版本引入了去重功能,以解決傳統B-Tree索引中一個常見的低效問題。當許多行共享相同的索引值(比如狀態碼、布爾標志或時間戳)時,標準的B-Tree會單獨存儲每個值及其對應的元組指針。這會導致索引頁膨脹,并增加維護成本,對于寫入密集型工作負載來說尤其如此。

PostgreSQL默認會對單個索引頁內的重復值進行去重處理。它不會多次存儲相同的鍵值,而是只存儲一次,并維護一個緊湊的結構來跟蹤所有匹配的堆指針。這能顯著減小索引大小,并提高緩存性能,因為更多的索引條目可以放入內存中。

SQL Server不支持去重。即使值完全相同,每個索引項也會獨立存儲。在分布傾斜的數據集中,PostgreSQL的方法能生成更緊湊、更高效的索引,頁面更少,磁盤I/O也更少。

在PostgreSQL與SQL Server上對B樹索引進行基準測試

為了了解PostgreSQL的索引去重功能對實際性能和存儲的影響,我們進行了一項基準測試,在不同的數據重復程度下比較PostgreSQL和SQL Server的B-Tree索引大小。每個測試都創建了一個包含1000萬行的表,這些行的值重復程度各不相同,從完全唯一的值到重復1000倍的值不等。

以下是我們在兩個數據庫中構建測試的方式,以便您可以自行復現該測試。

PostgreSQL測試設置

CREATE TABLE factor_1(col int);  
CREATE TABLE factor_10(col int);  
CREATE TABLE factor_100(col int);  
CREATE TABLE factor_1000(col int);INSERT INTO factor_1 SELECT * FROM GENERATE_SERIES(1, 10000000);  
INSERT INTO factor_10 SELECT val / 10 FROM GENERATE_SERIES(1, 10000000) x(val);  
INSERT INTO factor_100 SELECT val / 100 FROM GENERATE_SERIES(1, 10000000) x(val);  
INSERT INTO factor_1000 SELECT val / 1000 FROM GENERATE_SERIES(1, 10000000) x(val);CREATE INDEX factor_1_idx ON factor_1(col);  
CREATE INDEX factor_10_idx ON factor_10(col);  
CREATE INDEX factor_100_idx ON factor_100(col);  
CREATE INDEX factor_1000_idx ON factor_1000(col);CREATE INDEX factor_1_idx_no_dup_fill100 ON factor_1(col) WITH (deduplicate_items = off, fillfactor = 100);  
CREATE INDEX factor_10_idx_no_dup_fill100 ON factor_10(col) WITH (deduplicate_items = off, fillfactor = 100);  
CREATE INDEX factor_100_idx_no_dup_fill100 ON factor_100(col) WITH (deduplicate_items = off, fillfactor = 100);  
CREATE INDEX factor_1000_idx_no_dup_fill100 ON factor_1000(col) WITH (deduplicate_items = off, fillfactor = 100);  

SQL Server 測試設置

CREATE TABLE factor_1(col int);  
CREATE TABLE factor_10(col int);  
CREATE TABLE factor_100(col int);  
CREATE TABLE factor_1000(col int);INSERT INTO factor_1 SELECT * FROM GENERATE_SERIES(1, 10000000);  
INSERT INTO factor_10 SELECT value / 10 FROM GENERATE_SERIES(1, 10000000);  
INSERT INTO factor_100 SELECT value / 100 FROM GENERATE_SERIES(1, 10000000);  
INSERT INTO factor_1000 SELECT value / 1000 FROM GENERATE_SERIES(1, 10000000);CREATE INDEX factor_1_idx ON factor_1(col);  
CREATE INDEX factor_10_idx ON factor_10(col);  
CREATE INDEX factor_100_idx ON factor_100(col);  
CREATE INDEX factor_1000_idx ON factor_1000(col); 

基準測試結果:PostgreSQL的去重功能減小了索引大小

當我們對比PostgreSQL和SQL Server的索引大小時,發現隨著數據重復率的增加,兩者的差異顯著擴大。當值重復1000次時,啟用去重功能的PostgreSQL索引比關閉去重功能的相同索引小3倍。而SQL Server不支持去重功能,會完整存儲每個重復值,相比之下,PostgreSQL始終能生成更小、更高效的索引。

這種差異至關重要。在生產系統中,狀態標志、時間戳和分類字段等基數較高的列很常見。當這些值在數百萬行中重復出現時,大型索引會迅速成為性能瓶頸,導致掃描速度變慢、I/O 增加以及內存使用量膨脹。

PostgreSQL的去重功能顯著減小了索引大小,這使得索引更易于保存在內存中,并減輕了磁盤壓力。對于從SQL Server遷移到PostgreSQL的團隊,或者只是通過頻繁使用的索引來擴展工作負載的團隊而言,這種優化并非只是理論層面的。它對資源使用、查詢性能和整體運營效率都有著直接影響。

對比表:PostgreSQL 與 SQL Server 的索引

PostgreSQL和SQL Server在B樹及其他索引類型的索引實現上存在顯著差異。我們整理了一份全面的索引對比表,供您在從SQL Server遷移到PostgreSQL時參考。

(某些索引類型存在于SQL Server中,但不存在于PostgreSQL中,反之亦然。我們已按如下方式標注支持情況:🟢 支持的索引類型 🔴 不支持的索引類型。)

索引類型使用案例示例PostgreSQLSQL Server
B-Tree最適合通用索引、等值查詢和范圍查詢(例如,按年齡或日期篩選用戶)。🟢 默認索引類型,支持等值查詢和范圍查詢、排序以及帶前綴的模式匹配。🟢 在SQL Server上,聚集索引和非聚集索引的默認結構是B-Tree。
Clustered按索引鍵自動對表行進行排序;最適合頻繁排序的查詢。🔴 PostgreSQL 沒有聚簇索引;相反,您可以使用 CLUSTER 命令根據非聚簇索引對表進行排序;但是,當插入新數據時,這種順序不會被保留。🟢 相當于PostgreSQL的B樹;根據鍵對數據進行排序和存儲。
Nonclustered適用于可加快搜索速度且不影響物理存儲順序的索引。🟢 在PostgreSQL中,所有索引都是非聚集索引。🟢 可以在堆或聚集索引上創建;數據存儲與表分開。
Hash針對精確匹配查找進行了優化,例如按用戶ID或電子郵件地址搜索。🟢 在PostgreSQL中,哈希索引只能為單個列建立索引。雖然你可以創建多個索引來支持查詢,但通常多列B-Tree索引更為有效。🟢 用于內存優化表;需要固定的桶數量。
Filtered / Partial對數據子集(例如僅活躍用戶)進行索引時效率很高。🟢 PostgreSQL 可以使用部分索引僅對行的一個子集進行索引。🟢 篩選索引是一種非聚集索引,僅對表中的一部分行進行索引。
BRIN最適合數據自然有序的超大型表格,例如時間序列數據。🟢 存儲塊范圍的摘要;最適合大型、順序存儲的數據。🔴 N/A 🔴 不適用
Full-text用于自然語言搜索,例如搜索文章或產品評論中的文本。🟢 PostgreSQL支持通過在tsvector列上使用GIN索引來進行全文搜索。🟢 SQL Server 對基于文本的查詢使用倒排索引,類似于 PostgreSQL 的 GIN。
GIN非常適合為JSONB、數組和全文搜索建立索引(例如,搜索產品描述)。🟢 倒排索引;最適用于JSON、全文搜索和數組。🔴 通過全文索引實現部分功能。
Vector在高維數據中高效執行相似性搜索或最近鄰搜索,這在人工智能和機器學習應用中最為常見。🟢 PostgreSQL本身不包含向量支持,但開源擴展pgvector支持向量存儲和索引。🔴 SQL Server本身不支持向量索引或搜索。微軟建議改用其Azure AI搜索。
XML針對查詢和存儲XML文檔進行了優化。🔴 PostgreSQL 不直接支持在 XML 類型上創建索引;但是,可以在 XML 數據的子集上使用表達式索引。對于非結構化文檔,JSONB 是推薦的數據類型。🟢 SQL Server 對 XML 數據類型有專用索引。
Spatial用于地理查詢,例如查找半徑范圍內的位置。🟢 在PostgreSQL中,空間索引查詢由開源的PostGIS擴展提供。🟢 SQL Server 具有內置的空間數據類型。
SP-GiST用于層級數據結構,如基于樹的搜索(例如路由網絡)。🟢 支持非平衡樹結構,如四叉樹和k-d樹,適用于分層數據。🔴 N/A 🔴 不適用
GiST適用于幾何和全文搜索查詢,例如查找附近的位置。🟢 專用索引的基礎架構;用于幾何和全文搜索。🔴 N/A 🔴 不適用
Columnstore最適合OLAP工作負載和分析查詢(例如,數據倉庫)。🔴 雖然PostgreSQL有不同的擴展提供列式存儲,如Citus和Timescale,但這是一個相對較新的實現,可能會受使用場景的限制。🟢 自SQL Server 2012起,SQL Server就內置了作為索引類型實現的列存儲。

為你的工作選擇合適的索引

理解PostgreSQL和SQL Server索引之間的差異,在優化查詢性能、規劃遷移或設計高性能數據庫時至關重要。選擇合適的索引策略需要深入了解查詢執行模式和性能權衡。許多團隊會手動嘗試不同的索引策略,這可能導致過度索引、冗余索引或錯失優化機會。

與反復試驗不同,pganalyze 索引顧問通過針對真實查詢執行數據應用約束編程模型,自動檢測缺失的索引、冗余的索引以及多列索引的最佳列順序。這消除了猜測工作,確保PostgreSQL數據庫的索引設置能實現最佳性能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95647.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95647.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95647.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【微實驗】使用MATLAB制作一張賽博古琴?

當一個理工音樂人沒錢去買古琴,我直接用代碼畫一個古琴!目錄 零、總腳本: 一、核心功能:交互模塊拆解 二、核心價值 一、初始化腳本:參數配置與啟動界面 ①廢話不說,直接上代碼 ②代碼模塊拆解與詳細解…

畢業項目推薦:67-基于yolov8/yolov5/yolo11的大棚黃瓜檢測識別系統(Python+卷積神經網絡)

文章目錄 項目介紹大全(可點擊查看,不定時更新中)概要一、整體資源介紹技術要點功能展示:功能1 支持單張圖片識別功能2 支持遍歷文件夾識別功能3 支持識別視頻文件功能4 支持攝像頭識別功能5 支持結果文件導出(xls格式…

無人機小尺寸RFSOC ZU47DR板卡

整板尺寸:120*120mmFPGA: XCZU47DR-2FFVE1156I;DDR:PS側8GB 2400Mhz*64bit / PL側 4GB 2400Mhz*32bit;2路(QSP0QSPI1)/單片512Mb、共計1Gb;千兆以太網:1路(PS側);主要接口資源如下&a…

LangGraph(一):入門從0到1(零基礎)

文章目錄LangGraph入門從0到10?? 安裝 & 確認環境1?? 把 LangGraph 想象成「自動化的做菜流水線」2?? 最小可運行例子:一句話復讀機3?? 加一個小節點:把用戶輸入變大寫4?? 條件邊:如果用戶說 quit 就結束,否則復讀5…

學習數據結構(16)快速排序

快速排序的基本思想:快速排序是Hoare于1962年提出的一種二叉樹結構的交換排序方法,其基本思想為:任取待排序元素序列中的某元素作為基準值,按照該基準值將待排序集合分割成兩子序列,左子序列中所有元素均小于基準值&am…

uni-app iOS 上架常見問題與解決方案,實戰經驗全解析

uni-app 讓開發者能夠“一套代碼,多端運行”,極大降低了開發成本。 但當應用進入 iOS 上架階段 時,不少團隊發現流程并沒有想象中那么順利:證書問題、打包失敗、上傳出錯、審核被拒……這些都可能讓項目卡殼。 本文結合實際案例&a…

洗衣機的智能升級集成方案WT2606B屏幕驅動+AI語音控制

2025,洗衣機市場正從功能滿足轉向體驗升級,企業正面臨哪些轉型難點?一文為您解讀洗衣機行業智能化升級之路。傳統洗衣機就像是一個"沉默的工人",只能通過簡單的LED指示燈告訴你它在工作,卻無法讓你真正了解它在干嘛。用…

機器學習進階,梯度提升機(GBM)與XGBoost

梯度提升機(Gradient Boosting Machine, GBM),特別是其現代高效實現——XGBoost。這是繼隨機森林后自然進階的方向,也是當前結構化數據競賽和工業界應用中最強大、最受歡迎的算法之一。為什么推薦XGBoost? 與隨機森林互…

【ARMv7】開篇:掌握ARMv7架構Soc開發技能

本專欄,開始與大家共同總結使用ARMv7系列CPU的Soc開發技能。大概匯總了一下,后面再逐步完善下面的思維導圖。簡單說說:與通用的ARMv7-A/R相比,以STM32F為代表的ARMv7-M架構有以下關鍵區別和重點:無MMU,有MP…

【學術會議論文投稿】JavaScript在數據可視化領域的探索與實踐

【ACM出版 | EI快檢索 | 高錄用】2024年智能醫療與可穿戴智能設備國際學術會議(SHWID 2024)_艾思科藍_學術一站式服務平臺 更多學術會議請看 學術會議-學術交流征稿-學術會議在線-艾思科藍 目錄 引言 JavaScript可視化庫概覽 D3.js基礎入門 1. 引入…

CSS基礎學習步驟

好的,這是一份為零基礎初學者量身定制的 **CSS 學習基礎詳細步驟**。我們將從最根本的概念開始,通過一步一步的實踐,帶你穩穩地入門。 第一步:建立核心認知 - CSS 是做什么的? 1. 理解角色: HTML&…

MTK Linux DRM分析(三十七)- MTK phy-mtk-hdmi.c 和 phy-mtk-hdmi-mt8173.c

一、簡介 HDMI PHY驅動 HDMI 的物理層接口主要就是 HDMI Type-A 接口(19 pin),除此之外還有 Type-B、Type-C(Mini HDMI)、Type-D(Micro HDMI)、Type-E(車載專用)。 1. HDMI Type-A(常見 19-pin 標準接口) HDMI Type-A Connector Pinout ========================…

【人工智能學習之MMdeploy部署踩坑總結】

【人工智能學習之MMdeploy部署踩坑總結】報錯1:TRTNet: device must be a GPU!報錯2:Failed to create Net backend: tensorrt報錯3:Failed to load library libonnxruntime_providers_shared.so1. 確認庫文件是否存在2. 重新安裝 ONNX Runti…

力扣516 代碼隨想錄Day16 第一題

找二叉樹左下角的值class Solution { public:int maxd0;int result;void traversal(TreeNode* root,int depth){if(root->leftNULL&&root->rightNULL){if(depth>maxd){maxddepth;resultroot->val;}}if(root->left){depth;traversal(root->left,depth…

網格圖--Day07--網格圖DFS--LCP 63. 彈珠游戲,305. 島嶼數量 II,2061. 掃地機器人清掃過的空間個數,489. 掃地機器人,2852. 所有單元格的遠離程度之和

網格圖–Day07–網格圖DFS–LCP 63. 彈珠游戲,305. 島嶼數量 II,2061. 掃地機器人清掃過的空間個數,489. 掃地機器人,2852. 所有單元格的遠離程度之和 今天要訓練的題目類型是:【網格圖DFS】,題單來自靈茶山…

多功能修改電腦機器碼序列號工具 綠色版

多功能修改電腦機器碼序列號工具 綠色版電腦機器碼序列號修改軟件是一款非常使用的數據化虛擬修改工具。機器碼修改軟件可以虛擬的定制您電腦上的硬件信息,軟件不會對您的電腦造成傷害。軟件不需要您有專業的知識,就可以模擬一份硬件信息。機器碼修改軟…

React Hooks深度解析:useState、useEffect及自定義Hook最佳實踐

React Hooks自16.8版本引入以來,徹底改變了我們編寫React組件的方式。它們讓函數組件擁有了狀態管理和生命周期方法的能力,使代碼更加簡潔、可復用且易于測試。本文將深入探討三個最重要的Hooks:useState、useEffect,以及如何創建…

期權平倉后權利金去哪了?

本文主要介紹期權平倉后權利金去哪了?期權平倉后權利金的去向需結合交易角色(買方/賣方)、平倉方式及市場價格變動綜合分析,具體可拆解為以下邏輯鏈條。期權平倉后權利金去哪了?1. 買方平倉:權利金的“差價…

2025國賽C題題目及最新思路公布!

C 題 NIPT 的時點選擇與胎兒的異常判 問題 1 試分析胎兒 Y 染色體濃度與孕婦的孕周數和 BMI 等指標的相關特性,給出相應的關系模 型,并檢驗其顯著性。 思路1:針對附件中孕婦的 NIPT 數據,首先對數據進行預處理,并對多…

NLP技術爬取

“NLP技術爬取”這個詞組并不指代一種單獨的爬蟲技術,而是指將自然語言處理(NLP)技術應用于網絡爬蟲的各個環節,以解決傳統爬蟲難以處理的問題,并從中挖掘出更深層次的價值。簡單來說,它不是指“用NLP去爬”…