(六)重建表與count 原理

2021-10-08 19:01:43 字數 1596 閱讀 7188

delete 命令其實只是把記錄的位置,或者資料頁標記為了可復用」,但磁碟檔案的大小是不會變的。也就是說,通過 delete 命令是不能**表空間的。這些可以復用,而沒有被使用的空間,看起來就像是「空洞」。

不止是刪除資料會造成空洞,插入資料也會。

經過大量增刪改的表,都是可能是存在空洞的。所以,如果能夠把這些空洞去掉,就能達到收縮表空間的目的。而重建表,就可以達到這樣的目的。

可以使用alter table a engine=innodb命令來重建表:其本質就是將a中的資料一條條複製到臨時表中,全部複製完後用臨時表來替換原表

為了在該過程中也允許增刪改操作,mysql 5.6 版本開始引入的 online ddl,對這個操作流程做了優化:

建立乙個臨時檔案,掃瞄表 a 主鍵的所有資料頁;

用資料頁中表 a 的記錄生成 b+ 樹,儲存到臨時檔案中;

生成臨時檔案的過程中,將所有對 a 的操作記錄在乙個日誌檔案(row log)中;

臨時檔案生成後,將日誌檔案中的操作應用到臨時檔案,得到乙個邏輯資料上與表 a 相同的資料檔案;

用臨時檔案替換表 a 的資料檔案。

alter 語句在啟動的時候需要獲取 mdl 寫鎖,但是這個寫鎖在真正拷貝資料之前就退化成讀鎖了。

需要補充說明的是,上述的這些重建方法都會掃瞄原表資料和構建臨時檔案。對於很大的表來說,這個操作是很消耗 io 和 cpu 資源的。因此,如果是線上服務,你要很小心地控制操作時間。如果想要比較安全的操作的話,我推薦你使用 github 開源的 gh-ost 來做。

alter table t engine = innodb(也就是 recreate)預設的就是上面的流程;

analyze table t 其實不是重建表,只是對錶的索引資訊做重新統計,沒有修改資料,這個過程中加了 mdl 讀鎖;

optimize table t 等於 recreate+analyze。

在不同的 mysql 引擎中,count(*) 有不同的實現方式。

為什麼 innodb 不跟 myisam 一樣,也把數字存起來呢

這是因為即使是在同乙個時刻的多個查詢,由於多版本併發控制(mvcc)的原因,innodb 表「應該返回多少行」也是不確定的,innodb 只好把資料一行一行地讀出依次判斷,可見的行才能夠用於計算「基於這個查詢」的表的總行數。

mysql,在執行 count(*) 操作的時候還是做了優化的。你知道的,innodb 是索引組織表,主鍵索引樹的葉子節點是資料,而普通索引樹的葉子節點是主鍵值。所以,普通索引樹比主鍵索引樹小很多。對於 count() *這樣的操作,遍歷哪個索引樹得到的結果邏輯上都是一樣的。因此,mysql 優化器會找到最小的那棵樹來遍歷

用快取系統儲存計數,但是拿到的數不一定準確,因為這兩個不同的儲存構成的系統,不支援分布式事務,無法拿到精確一致的檢視

在資料庫儲存計數,把這個計數直接放到資料庫裡單獨的一張計數表 c,借助事務的隔離性可以讀到準確的值

P1272 重建道路

p1272 重建道路 題意 有一棵n個點的樹,求刪掉最少的邊數,使得其中p個點的子樹和另一部分分離 dp i j 表示編號為i的點周圍組成j個點的樹最少要刪的邊數 初始狀態 dp i 1 連線這個點的邊數 每個點都是點數為1的樹 然後去考慮連線兩個點,使子樹的點數增多。有兩個點數都是1的樹dp i ...

jzoj1212 重建道路

分析code 第一行有乙個整數n 2 n 100 表示有多少個城市。城市的編號是1 n。第二行有乙個整數m n 1 m n n 1 2,表示有多少條道路。接下來有m行,每行3個整數,x,y,len 1 x,y n,x y.0 len 100 表示城市x和城市y有一條長度為len的雙向道路。再接下來的...

SDOI 2014 重建 題解

題目傳送門 題目大意 給出一張圖,過後每條邊有乙個存在的概率,問 後圖變樹的概率。又長見識了 還有個變元矩陣樹定理。對於圖的一棵生成樹,它的出現概率為 存在的邊的 p i p i p i 之積乘不存在的邊的 1 p i 1 p i 1 p i 之積。設圖為 g gg,生成樹為 t tt,那麼用柿子表...