1. 程式人生 > >(十) 資料庫查詢處理之排序(sorting)

(十) 資料庫查詢處理之排序(sorting)

### 1. 為什麼我們需要對資料排序 1. 可以支援對於重複元素的清除(支援DISTINCT) 2. 可以支援GROUP BY 操作 3. 對於關係運算中的一些運算能夠得到高效的實現 ### 2. 引入外部排序演算法 對於不能全部放在記憶體中的關係的排序。就需要引入外排序,其中最常用的技術就是外部歸併排序。 外部排序分為兩個階段 **Phase1 - Sorting** 對主存中的資料塊進行排序,然後將排序後的資料塊寫回磁碟。 **Phase2 - Merging** 將已排序的子檔案合併成一個較大的檔案 #### 2.1 N-way 外部歸併排序 從2路歸併排序開始。來引出N路歸併排序演算法 可以見下圖 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200344258-1545503825.png) ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200357675-1827559063.png) 對於簡單的二路歸併。我們有兩個buffer可以用。一個用來放輸入進行排序得到歸併塊。而另一個則用來放輸出 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200406348-595161654.png) 下面來分析一下二路歸併的時間複雜度 在每一個階段我們都需要把歸併塊從磁碟中讀入。然後在寫回磁碟因此總共的I/O次數就是階段數 * 2 階段數可以很容易的得到為 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200422651-1775877344.png) 可以很容易的發現上面的問題主要出現在。由於我們的輸入緩衝區只能放一個page。所以這導致了我們不停的進行換入換出導致了io次數變得非常多。優化方法就是加大緩衝區大小。減少階段數。這就需要我們歸併路數增大。 **使用B buffer pages** 這樣我們的輸入緩衝區就可以放B - 1個page。這樣我們的階段數就可以減少了。 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200431970-1224313100.png) #### **2.2 利用索引進行加速** 如果我們的table中已經有了B+樹索引。那麼我們可以利用它進行優化。 這裡有兩種情況需要被考慮 1. **聚簇索引** 資料的實體地址順序和索引的順序是一致的。 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200445678-1282003069.png) 這種方法比外部排序要好,因為它沒有額外的計算。比如不需要進行sort。不需要進行歸併。而且所有的磁碟訪問都是順序的。 2. **非聚簇索引** 資料的實體地址順序和索引的順序是不一致的。 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200502290-338758226.png) 如果是這樣的索引。就利用外部排序就好。 #### 2.3 AGGREGATIONS 將多個元組摺疊為單個標量值。有兩種實現方法 **1. 排序** 排序之後相同的元素就會在排在一起。這樣就可以去除冗餘元素 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200557213-840001256.png) **2. hash** 但是如果我們不要求資料是有序的。這樣我們排序就相當於浪費了時間。因為排序起碼要花費nlogn的時間。比如`GROUP BY ` 和`DISTINCT`操作。在這種情況下。hashing就是一個更好的選擇 **1. Partition** 假設我們有B buffers。其中B - 1個buffer用來partitions而1個buffer用來儲存輸出data。 第一階段就是利用一個hash函式。把tuple雜湊到不同的桶中。 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200752086-424956275.png) **2. Rehash** 由於階段1之後。擁有相同cid值的tuple都被對映到了相同的桶內。這個階段我們對不同的桶在進行一次hash。就可以完成我們的去重操作。 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200615037-1533783057.png) 當然利用hash操作不僅可以進行去重還可以進行其他的操作。如MAX、MIN、AVG、COUNT、SUM等 下面這張圖演示了count操作和sum操作。 ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200628002-1764701626.png) 這張圖演示了avg操作就是利用 sum / count ![](https://img2020.cnblogs.com/blog/2282357/202102/2282357-20210222200638396-1496726329.png) 這個算是結合cmu15-445課程和對應的教材、ppt進行的總結。順序從10開始是因為現在正好看到這裡。而之前忘了整理了。會在後面所有的都看完之後進行整