版本:MySQL5.7
創建一張測試表:
1
2
3
4
5
6
7
8
9
10
|
create
table
abce_comp(
id
bigint
(20) unsigned
not
null
,
identification_id
int
(10) unsigned
default
null
,
timestamp
datetime
not
null
,
action
varchar
(50)
not
null
,
result
varchar
(50)
not
null
,
primary
key
(id),
key
index_abce_comp_result(result),
key
index_abce_comp_timestamp(
timestamp
)
);
|
插入10萬行數據,用於測試:
1
|
for
NUM
in
{1..100000}; do mysql -uroot -p
"xxxxxxxx"
abce -e
"insert into abce_comp (id, identification_id, timestamp, action, result) values ($NUM,$NUM*100,now(),concat('string',$NUM),concat('VeryVeryLargeString',$NUM))"
; done
|
我們來看看錶的大小。再執行analyze table之前,將innodb_stats_persistent_sample_pages=100000。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
>
set
global
innodb_stats_persistent_sample_pages=100000;
Query OK, 0
rows
affected (0.00 sec)
> analyze
table
abce_comp;
+
----------------+---------+----------+----------+
|
Table
| Op | Msg_type | Msg_text |
+
----------------+---------+----------+----------+
| abce.abce_comp | analyze | status | OK |
+
----------------+---------+----------+----------+
1 row
in
set
(0.08 sec)
>
select
table_schema, table_name, table_rows,(data_length+index_length+data_free)/1024/1024 TOTAL_MB, create_options
from
information_schema.tables
where
table_name=
'abce_comp'
;
+
--------------+------------+------------+-------------+----------------+
| table_schema | table_name | table_rows | TOTAL_MB | create_options |
+
--------------+------------+------------+-------------+----------------+
| abce | abce_comp | 100000 | 22.57812500 | |
+
--------------+------------+------------+-------------+----------------+
1 row
in
set
(0.00 sec)
|
現在,開始壓縮表,將key_block_size設置成4(塊大小是我隨機選的)。
1
2
3
|
>
alter
table
abce_comp row_format=compressed,key_block_size=4,algorithm=inplace,lock=none;
Query OK, 0
rows
affected (1.98 sec)
Records: 0 Duplicates: 0 Warnings: 0
|
按照上面的步驟,再次收集表的統計信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
>
set
global
innodb_stats_persistent_sample_pages=100000;
Query OK, 0
rows
affected (0.00 sec)
> analyze
table
abce_comp;
+
----------------+---------+----------+----------+
|
Table
| Op | Msg_type | Msg_text |
+
----------------+---------+----------+----------+
| abce.abce_comp | analyze | status | OK |
+
----------------+---------+----------+----------+
1 row
in
set
(0.06 sec)
>
select
table_schema, table_name, table_rows,(data_length+index_length+data_free)/1024/1024 TOTAL_MB, create_options
from
information_schema.tables
where
table_name=
'abce_comp'
;
+
--------------+------------+------------+------------+----------------------------------------+
| table_schema | table_name | table_rows | TOTAL_MB | create_options |
+
--------------+------------+------------+------------+----------------------------------------+
| abce | abce_comp | 100000 | 7.14843750 | row_format=COMPRESSED KEY_BLOCK_SIZE=4 |
+
--------------+------------+------------+------------+----------------------------------------+
1 row
in
set
(0.00 sec)
|
可以看到,表已經被壓縮了。再來看看錶的結構:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
> show
create
table
abce_comp\G
*************************** 1. row ***************************
Table
: abce_comp
Create
Table
:
CREATE
TABLE
`abce_comp` (
`id`
bigint
(20) unsigned
NOT
NULL
,
`identification_id`
int
(10) unsigned
DEFAULT
NULL
,
`
timestamp
` datetime
NOT
NULL
,
`
action
`
varchar
(50)
NOT
NULL
,
`result`
varchar
(50)
NOT
NULL
,
PRIMARY
KEY
(`id`),
KEY
`index_abce_comp_result` (`result`),
KEY
`index_abce_comp_timestamp` (`
timestamp
`)
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8mb4 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4
1 row
in
set
(0.00 sec)
|
如何給表取消壓縮呢?是不是應該很簡單。
1
2
3
|
>
alter
table
abce_comp row_format=
default
,algorithm=inplace,lock=none;
Query OK, 0
rows
affected (1.85 sec)
Records: 0 Duplicates: 0 Warnings: 0
|
語句執行成功,看起來是起效果了:
1
2
3
4
5
6
|
>
select
table_schema, table_name, table_rows,(data_length+index_length+data_free)/1024/1024 TOTAL_MB, create_options
from
information_schema.tables
where
table_name=
'abce_comp'
;
+
--------------+------------+------------+------------+------------------+
| table_schema | table_name | table_rows | TOTAL_MB | create_options |
+
--------------+------------+------------+------------+------------------+
| abce | abce_comp | 100000 | 7.14843750 | KEY_BLOCK_SIZE=4 |
+
--------------+------------+------------+------------+------------------+
|
再看看錶結構:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
> show
create
table
abce_comp\G
*************************** 1. row ***************************
Table
: abce_comp
Create
Table
:
CREATE
TABLE
`abce_comp` (
`id`
bigint
(20) unsigned
NOT
NULL
,
`identification_id`
int
(10) unsigned
DEFAULT
NULL
,
`
timestamp
` datetime
NOT
NULL
,
`
action
`
varchar
(50)
NOT
NULL
,
`result`
varchar
(50)
NOT
NULL
,
PRIMARY
KEY
(`id`),
KEY
`index_abce_comp_result` (`result`),
KEY
`index_abce_comp_timestamp` (`
timestamp
`)
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8mb4 KEY_BLOCK_SIZE=4
|
哪裏出了點差錯,表的KEY_BLOCK_SIZE仍然是4。
再來一次嘗試:
1
2
3
|
>
alter
table
abce_comp row_format=
default
,key_block_size=0,algorithm=inplace,lock=none;
Query OK, 0
rows
affected (0.91 sec)
Records: 0 Duplicates: 0 Warnings: 0
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
>
select
table_schema, table_name, table_rows,(data_length+index_length+data_free)/1024/1024 TOTAL_MB, create_options
from
information_schema.tables
where
table_name=
'abce_comp'
;
+
--------------+------------+------------+-------------+----------------+
| table_schema | table_name | table_rows | TOTAL_MB | create_options |
+
--------------+------------+------------+-------------+----------------+
| abce | abce_comp | 100000 | 18.54687500 | |
+
--------------+------------+------------+-------------+----------------+
> show
create
table
abce_comp\G
*************************** 1. row ***************************
Table
: abce_comp
Create
Table
:
CREATE
TABLE
`abce_comp` (
`id`
bigint
(20) unsigned
NOT
NULL
,
`identification_id`
int
(10) unsigned
DEFAULT
NULL
,
`
timestamp
` datetime
NOT
NULL
,
`
action
`
varchar
(50)
NOT
NULL
,
`result`
varchar
(50)
NOT
NULL
,
PRIMARY
KEY
(`id`) KEY_BLOCK_SIZE=4,
KEY
`index_abce_comp_result` (`result`) KEY_BLOCK_SIZE=4,
KEY
`index_abce_comp_timestamp` (`
timestamp
`) KEY_BLOCK_SIZE=4
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8mb4
|
又出錯了!主鍵和輔助索引仍然是KEY_BLOCK_SIZE=4
儘管當表從壓縮轉換爲非壓縮表時,索引的KEY_BLOCK_SIZE在內部會遵循表的索引,但CREATE TABLE語句不會。起初這是一個美學/外觀問題,但是當你進行dump時這是一個真正的問題,因爲CREATE TABLE留下了KEY_BLOCK_SIZE值,這一點很不好。這是mysqldump的輸出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# mysqldump -uroot -pxxxxxxxx abce abce_comp
--no-data > abce_comp.sql
# more abce_comp.sql
-- MySQL dump 10.13 Distrib 5.7.37, for linux-glibc2.12 (x86_64)
--
-- Host: localhost Database: abce
-- ------------------------------------------------------
-- Server version 5.7.37-log
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */
;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */
;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */
;
/*!40101 SET NAMES utf8 */
;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */
;
/*!40103 SET TIME_ZONE='+00:00' */
;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */
;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */
;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */
;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */
;
SET
@MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET
@@SESSION.SQL_LOG_BIN= 0;
--
-- Table structure for table `abce_comp`
--
DROP
TABLE
IF EXISTS `abce_comp`;
/*!40101 SET @saved_cs_client = @@character_set_client */
;
/*!40101 SET character_set_client = utf8 */
;
CREATE
TABLE
`abce_comp` (
`id`
bigint
(20) unsigned
NOT
NULL
,
`identification_id`
int
(10) unsigned
DEFAULT
NULL
,
`
timestamp
` datetime
NOT
NULL
,
`
action
`
varchar
(50)
NOT
NULL
,
`result`
varchar
(50)
NOT
NULL
,
PRIMARY
KEY
(`id`) KEY_BLOCK_SIZE=4,
KEY
`index_abce_comp_result` (`result`) KEY_BLOCK_SIZE=4,
KEY
`index_abce_comp_timestamp` (`
timestamp
`) KEY_BLOCK_SIZE=4
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8mb4;
/*!40101 SET character_set_client = @saved_cs_client */
;
--
-- GTID state at the end of the backup
--
SET
@@
GLOBAL
.GTID_PURGED=
'10ccf388-efb0-11ec-b477-08002762387f:1-100014'
;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */
;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */
;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */
;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */
;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */
;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */
;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */
;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */
;
-- Dump completed on 2022-07-11 21:49:52
|
如你所見,似乎無法使用全局ALTER TABLE命令(如果我們可以這樣稱呼它)來反轉表定義中的索引的key_block_size,因此我們將進行最後一次嘗試:
1
2
3
4
5
|
>
alter
table
abce_comp
->
drop
primary
key
,
add
primary
key
(id),
->
drop
key
index_abce_comp_result,
add
key
index_abce_comp_result (result),
->
drop
key
index_abce_comp_timestamp,
add
key
index_abce_comp_timestamp (
timestamp
),
-> row_format=
default
,key_block_size=0,algorithm=inplace,lock=none;
|
現在再看看結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
> show
create
table
abce_comp\G
*************************** 1. row ***************************
Table
: abce_comp
Create
Table
:
CREATE
TABLE
`abce_comp` (
`id`
bigint
(20) unsigned
NOT
NULL
,
`identification_id`
int
(10) unsigned
DEFAULT
NULL
,
`
timestamp
` datetime
NOT
NULL
,
`
action
`
varchar
(50)
NOT
NULL
,
`result`
varchar
(50)
NOT
NULL
,
PRIMARY
KEY
(`id`),
KEY
`index_abce_comp_result` (`result`),
KEY
`index_abce_comp_timestamp` (`
timestamp
`)
) ENGINE=InnoDB
DEFAULT
CHARSET=utf8mb4
1 row
in
set
(0.00 sec)
>
select
table_schema, table_name, table_rows,(data_length+index_length+data_free)/1024/1024 TOTAL_MB, create_options
from
information_schema.tables
where
table_name=
'abce_comp'
;
+
--------------+------------+------------+-------------+----------------+
| table_schema | table_name | table_rows | TOTAL_MB | create_options |
+
--------------+------------+------------+-------------+----------------+
| abce | abce_comp | 100000 | 18.54687500 | |
+
--------------+------------+------------+-------------+----------------+
|
顯然,這是一個bug:https://bugs.mysql.com/bug.php?id=56628
在MySQL 5.7中,完全還原的唯一方法(至少在表及其索引的定義中)是重新生成主鍵及其所有索引。這聽起來像是一個終端解決方案,但如果你使用mysqldump進行備份(我們總是建議使用 Percona XtraBackup 來實現這些目的,它更快更高效)這是一個需要考慮的問題,因爲它在其定義中保留了那些錯誤的定義。
幸運的是,這在MySQL 8中已修復。MySQL 8中,執行以下語句,就可以將壓縮錶轉換成非壓縮表
1
|
>
alter
table
abce_comp ROW_FORMAT=
DEFAULT
, KEY_BLOCK_SIZE=0,ALGORITHM=INPLACE,LOCK=NONE;
|