主鍵的大小是否會影響表的大小?
我有一個表(InnoDB),數據長度約為 36G,索引長度為 23G。
它有一個跨三列的複合主鍵。
作為減小該表大小的最初嘗試,我刪除了主鍵(實際上並不需要)。然而,數據長度和索引長度是相同的。
這是可以預料的嗎?
在此數據庫上啟用了更新innodb_file_per_table
更新
mysql> show create table event; CREATE TABLE `event` ( `owner_id` varchar(36) NOT NULL, `key_id` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, KEY `owner_id_idx` (`owner_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8
簡短的回答
實際上是相反的:表的大小會影響主鍵的大小。因此,是的,這是意料之中的。
長答案
主鍵位於gen_clust_index中,也就是聚集索引。
根據MySQL Documentation on the Clustered Index
聚集索引如何加速查詢
通過聚集索引訪問行速度很快,因為行數據位於索引搜尋引導的同一頁上。如果表很大,與使用與索引記錄不同的頁面儲存行數據的儲存組織相比,聚集索引架構通常會節省磁碟 I/O 操作。(例如,MyISAM 將一個文件用於數據行,將另一個文件用於索引記錄。)
根據這個描述,InnoDB 儲存引擎的每一行都位於聚集索引內。
鑑於此,需要回答兩個問題:
- 為什麼刪除 PRIMARY KEY 不會縮小聚集索引?
- 為什麼 OPTIMIZE TABLE 不收縮聚集索引?
這兩個問題的答案都只有一個。關於聚集索引的 MySQL 文件說:
如果表沒有 PRIMARY KEY 或合適的 UNIQUE 索引,InnoDB 在內部生成一個隱藏的聚集索引,該索引包含行 ID 值的合成列。這些行按 InnoDB 分配給此類表中的行的 ID 排序。行 ID 是一個 6 字節的欄位,隨著新行的插入而單調增加。因此,按行 ID 排序的行在物理上是按插入順序排列的。
想一想:
OPTIMIZE TABLE
由於您沒有嘗試刪除任何行,因此變得無效。由於您沒有刪除任何行,因此行佔用的所有空間仍將位於聚集索引內。您只需將一個密鑰(您的主密鑰)換成另一個(6 字節行 ID)。縮小聚集索引的方法有哪些?
我有您可能需要做的三 (3) 種技術之一
技巧#1:減少你的列的長度
- 縮小
INTs
到 SMALLINT 或 TINYINT- 縮小
VARCHAR(255)
到VARCHAR(128)
技巧#2:刪除舊行
查找具有非常舊時間戳的行,然後
- 刪除舊行
- 將舊行存檔在另一個表中
技巧#3:從表中刪除列
- 這在理論上是正確的
- 沒有人願意在流程中失去數據
- 在刪除列之前存檔表
警告
在應用這三 (3) 種技術之一之前,請備份您的表。
結語
一旦應用了這三 (3) 種技術中的一種,您就可以執行以下操作之一來縮小聚集索引(例如,
mydb.mytable
):
OPTIMIZE TABLE mydb.mytable;
ALTER TABLE mydb.mytable ENGINE=InnoDB;
試一試 !!!
更新 2013-06-17 07:34 EDT
這是你的最後一條評論
因此,如果原始主鍵大於 6 字節,我不會期望看到聚集索引大小減少嗎?
即使
PRIMARY KEY
是 nowCHAR(255)
,每一行都位於聚集索引內。InnoDB 中的每個頁面是 16K。6 字節的行 ID(InnoDB 仍然在內部使用)仍然嵌入在相同的頁面中。刪除PRIMARY KEY
它更像是一種邏輯刪除而不是物理刪除。這就是為什麼我之前說您只需將一個密鑰(您的主密鑰)換成另一個(6 字節行 ID)
刪除的物理行為
PRIMARY KEY
可能需要在墓碑(標記)每一行時執行到每一行,而不是使用一些內部列組合,PRIMARY KEY
而是恢復到行 ID。這幾乎不會改變 16K InnoDB 頁面的使用,無論行長度是長的(可能允許頁面中的幾行)或短的(可能允許頁面中的更多行)。執行
OPTIMIZE TABLE
縮小它仍然不會產生任何明顯的變化,因為聚集索引的標記機制仍然存在。給定表中行的平均長度,完全相同的行數使聚集索引保持相同的大小。查看我之前提到的三種技術以及MySQL Documentation on the Clustered Index。鑑於表中的行數和您目前的表定義,如果您無法減小列大小、刪除列、刪除行並將它們歸檔到其他地方,那麼您無法縮小表。