大家好,我们都知道在MySQL中表压缩的好处,以目前的技术,处理速度和压缩磁盘,在大多数情况下,这是一个好处。
那么,如果没有这种情况会发生什么呢?
在这个简单的博客中,我将向您展示一些有趣的事情,当您试图从压缩表转换到普通表时,会发生这种情况。我们不打算详细讨论或讨论其他问题,例如:为什么表被压缩是件坏事?性能如何,系统性能如何,甚至不包括压缩需要消耗多少硬件资源?我们也不打算讨论内存中的页面是压缩的、未压缩的,还是两者都有。这已经讨论得够多了,你可以在我们的网站上找到一些非常有趣的博客,甚至在文档中也可以找到。
我将向您展示的是一些非常有趣的东西,为此,我们将从头到尾以一种您可以自己完成的方式执行这个练习(好吧,除了数据加载部分,呵呵!),我将给出一个示例脚本(稍后)。
让我们在数据库实例中创建表雷竞技下载官网Percona Server for MySQL 5.7安装。
|
1
2
3.
4
5
6
7
8
9
10
11
|
CentOS7-S1
PS_57
>
创建
表格
test_compress
(
id
长整型数字
(
20.
)
无符号
不
零
,
identification_id
int
(
10
)
无符号
默认的
零
,
时间戳
datetime
不
零
,
行动
varchar
(
50
)
不
零
,
结果
varchar
(
50
)
不
零
,
主要的
关键
(
id
)
,
关键
INDEX_test_compress_result
(
结果
)
,
关键
INDEX_test_compress_timestamp
(
时间戳
)
)
引擎=InnoDB
默认的
字符集=latin1
;
查询
好吧
,
0
行
影响
(
0.02
证券交易委员会
)
|
之后,让我们用一些数据(100,000行)加载表。
|
1
|
CentOS7-S1
$
为
全国矿工工会
在
{
1 . . 100000
}
;
做
mysql
-h
本地主机
PS_57
-e
"insert into test_compress (id, identification_id, timestamp, action, result) values ($NUM,$NUM*100,now(),concat('string',$NUM),concat('VeryVeryLargeString',$NUM))"
;
完成
|
让我们验证表的大小(之前使用innodb_stats_persistent_sample_pages=100000执行ANALYZE table,以便统计数据尽可能真实)。
|
1
|
CentOS7-S1
PS_57
>
集
全球
innodb_stats_persistent_sample_pages=100000
;
查询
好吧
,
0
行
影响
(
0.00
证券交易委员会
)
|
|
1
2
3.
4
5
6
7
|
CentOS7-S1
PS_57
>
分析
表格
test_compress
;
+------------------------+---------+----------+----------+
|
表格
|
人事处
|
Msg_type
|
Msg_text
|
+------------------------+---------+----------+----------+
|
PS_57
.test_compress
|
分析
|
状态
|
好吧
|
+------------------------+---------+----------+----------+
查询
好吧
,
0
行
影响
(
0.00
证券交易委员会
)
|
|
1
2
3.
4
5
6
|
CentOS7-S1
PS_57
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+----------------+
|
table_schema
|
table_name
|
table_rows
|
TOTAL_MB
|
create_options
|
+--------------+---------------+------------+----------+----------------+
|
PS_57
|
test_compress
|
100000
|
37
|
|
+--------------+---------------+------------+----------+----------------+
|
接下来,我们将用KEY_BLOCK_SIZE=4压缩表(这个大小是任意选择的,在任何时候都没有指示或决定它是否是最佳值,事实上,它不是)。
|
1
2
|
CentOS7-S1
PS_57
>
改变
表格
test_compress
ROW_FORMAT=压缩
,
KEY_BLOCK_SIZE=4
,
算法=原地
,
锁=没有一个
;
查询
好吧
,
0
行
影响
(
3.33
证券交易委员会
)
|
我们再次验证表的大小(之前使用innodb_stats_persistent_sample_pages=100000执行ANALYZE table,以便统计数据尽可能真实)。
|
1
2
|
CentOS7-S1
PS_57
>
集
全球
innodb_stats_persistent_sample_pages=100000
;
查询
好吧
,
0
行
影响
(
0.00
证券交易委员会
)
|
|
1
2
3.
4
5
6
7
|
CentOS7-S1
PS_57
>
分析
表格
test_compress
;
+------------------------+---------+----------+----------+
|
表格
|
人事处
|
Msg_type
|
Msg_text
|
+------------------------+---------+----------+----------+
|
PS_57
.test_compress
|
分析
|
状态
|
好吧
|
+------------------------+---------+----------+----------+
查询
好吧
,
0
行
影响
(
0.00
证券交易委员会
)
|
|
1
2
3.
4
5
6
|
CentOS7-S1
PS_57
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+----------------------------------------+
|
table_schema
|
table_name
|
table_rows
|
TOTAL_MB
|
create_options
|
+--------------+---------------+------------+----------+----------------------------------------+
|
PS_57
|
test_compress
|
100000
|
19
|
row_format=压缩
KEY_BLOCK_SIZE=4
|
+--------------+---------------+------------+----------+----------------------------------------+
|
正如您所看到的,表已经被压缩了,让我们检查一下它的结构。
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
14
|
CentOS7-S1
PS_57
>
显示
创建
表格
test_compress
\
G
***************************
1.
行
***************************
表格
:
test_compress
创建
表格
:
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
(
20.
)
无符号
不
零
,
`
identification_id
`
int
(
10
)
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
)
引擎=InnoDB
默认的
字符集=latin1
ROW_FORMAT=压缩
KEY_BLOCK_SIZE=4
1
行
在
集
(
0.00
证券交易委员会
)
|
我们如何逆转压缩?好问题。应该很简单,对吧?
(澄清一下,在你问之前,我们不会根据表的大小来判断应该怎么做,这个ALTER会对复制产生什么影响,以及其他事情,我们的想法是展示如何反转它,而不是其他。)
我们可以使用这个命令,让我们看看:
|
1
2
3.
|
CentOS7-S1
PS_57
>
改变
表格
test_compress
ROW_FORMAT=默认的
,
算法=原地
,
锁=没有一个
;
查询
好吧
,
0
行
影响
(
6.25
证券交易委员会
)
记录
:
0
重复的
:
0
警告
:
0
|
这似乎起作用了!未压缩的:
|
1
2
3.
4
5
6
|
CentOS7-S1
PS_57
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+--------------------+
|
table_schema
|
table_name
|
table_rows
|
TOTAL_MB
|
create_options
|
+--------------+---------------+------------+----------+--------------------+
|
PS_57
|
test_compress
|
100000
|
25
|
KEY_BLOCK_SIZE=4
|
+--------------+---------------+------------+----------+--------------------+
|
更好的检查:
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
|
CentOS7-S1
PS_57
>
显示
创建
表格
test_compress
\
G
***************************
1.
行
***************************
表格
:
test_compress
创建
表格
:
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
(
20.
)
无符号
不
零
,
`
identification_id
`
int
(
10
)
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
)
引擎=InnoDB
默认的
字符集=latin1
KEY_BLOCK_SIZE=4
|
有点不对劲!KEY_BLOCK_SIZE仍然是4。
第二次尝试:
|
1
2
3.
|
CentOS7-S1
PS_57
>
改变
表格
test_compress
ROW_FORMAT=默认的
,
KEY_BLOCK_SIZE=0
,
算法=原地
,
锁=没有一个
;
查询
好吧
,
0
行
影响
(
2.05
证券交易委员会
)
记录
:
0
重复的
:
0
警告
:
0
|
|
1
2
3.
4
5
6
|
CentOS7-S1
PS_57
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+--------------------+
|
table_schema
|
table_name
|
table_rows
|
TOTAL_MB
|
create_options
|
+--------------+---------------+------------+----------+--------------------+
|
PS_57
|
test_compress
|
100000
|
25
|
|
+--------------+---------------+------------+----------+--------------------+
|
更好的检查:
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
|
CentOS7-S1
PS_57
>
显示
创建
表格
test_compress
\
G
***************************
1.
行
***************************
表格
:
test_compress
创建
表格
:
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
(
20.
)
无符号
不
零
,
`
identification_id
`
int
(
10
)
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
KEY_BLOCK_SIZE=4
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
KEY_BLOCK_SIZE=4
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
KEY_BLOCK_SIZE=4
)
引擎=InnoDB
默认的
字符集=latin1
|
有点不对劲!主键和辅助索引都继续显示KEY_BLOCK_SIZE=4。
虽然当表从压缩转换为未压缩时,在内部索引的KEY_BLOCK_SIZE尊重表的KEY_BLOCK_SIZE,但CREATE table语句不这样做。一开始,这可能是一个美观/表面的问题,但当您执行转储时,这是一个真正的问题,因为CREATE TABLE留下了KEY_BLOCK_SIZE值,这并不好。下面是mysqldump的输出:
|
1
|
$
, mysqldump
-h
本地主机
PS_57
test_compress
--没有-数据
>
test_compress
. sql
|
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20.
21
|
$
猫
test_compress
. sql
.
.
.
--
--
表格
结构
为
表格
`
test_compress
`
--
下降
表格
如果
存在
`
test_compress
`
;
/*!
40101
集
@
saved_cs_client
=
@
@
character_set_client
* /;
/*!
50503
集
character_set_client
=
utf8mb4
* /;
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
(
20.
)
无符号
不
零
,
`
identification_id
`
int
(
10
)
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
KEY_BLOCK_SIZE=4
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
KEY_BLOCK_SIZE=4
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
KEY_BLOCK_SIZE=4
)
引擎=InnoDB
默认的
字符集=latin1
;
/*!
40101
集
character_set_client
=
@
saved_cs_client
* /;
.
.
.
|
正如你所看到的,似乎没有办法用全局ALTER table命令(如果我们可以这样称呼它的话)来反转表定义索引中的KEY_BLOCK_SIZE,所以我们将做最后一次尝试:
|
1
2
3.
4
5
|
改变
表格
test_compress
下降
主要的
关键
,
添加
主要的
关键
(
id
)
,
下降
关键
INDEX_test_compress_result
,
添加
关键
INDEX_test_compress_result
(
结果
)
,
下降
关键
INDEX_test_compress_timestamp
,
添加
关键
INDEX_test_compress_timestamp
(
时间戳
)
,
ROW_FORMAT=默认的
,
KEY_BLOCK_SIZE=0
,
算法=原地
,
锁=没有一个
;
|
现在,它有了没有KEY_BLOCK_SIZE的正确定义:
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
14
|
CentOS7-S1
PS_57
>
显示
创建
表格
test_compress
\
G
***************************
1.
行
***************************
表格
:
test_compress
创建
表格
:
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
(
20.
)
无符号
不
零
,
`
identification_id
`
int
(
10
)
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
)
引擎=InnoDB
默认的
字符集=latin1
1
行
在
集
(
0.00
证券交易委员会
)
|
|
1
2
3.
4
5
6
|
CentOS7-S1
PS_57
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+----------------+
|
table_schema
|
table_name
|
table_rows
|
TOTAL_MB
|
create_options
|
+--------------+---------------+------------+----------+----------------+
|
PS_57
|
test_compress
|
100000
|
25
|
|
+--------------+---------------+------------+----------+----------------+
|
显然,MariaDB中存在与案件相关的bug:
https://jira.mariadb.org/browse/MDEV-26400
https://jira.mariadb.org/browse/MDEV-11757
MySQL中也有类似的情况:
https://bugs.mysql.com/bug.php?id=56628
在MySQL 8中,情况如下:
|
1
2
3.
4
5
6
|
CentOS7-S2
PS_8
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+----------------+
|
TABLE_SCHEMA
|
TABLE_NAME
|
TABLE_ROWS
|
TOTAL_MB
|
CREATE_OPTIONS
|
+--------------+---------------+------------+----------+----------------+
|
PS_8
|
test_compress
|
31000
|
15
|
|
+--------------+---------------+------------+----------+----------------+
|
让我们执行ALTER来压缩表:
|
1
2
3.
|
CentOS7-S2
PS_8
>
改变
表格
test_compress
ROW_FORMAT=压缩
,
KEY_BLOCK_SIZE=4
,
算法=原地
,
锁=没有一个
;
查询
好吧
,
0
行
影响
(
4.54
证券交易委员会
)
记录
:
0
重复的
:
0
警告
:
0
|
让我们再检查一下:
|
1
2
3.
4
5
6
7
|
CentOS7-S2
PS_8
>
分析
表格
test_compress
;
+-----------------------+---------+----------+----------+
|
表格
|
人事处
|
Msg_type
|
Msg_text
|
+-----------------------+---------+----------+----------+
|
PS_8
.test_compress
|
分析
|
状态
|
好吧
|
+-----------------------+---------+----------+----------+
1
行
在
集
(
0.07
证券交易委员会
)
|
|
1
2
3.
4
5
6
|
CentOS7-S2
PS_8
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+----------------------------------------+
|
TABLE_SCHEMA
|
TABLE_NAME
|
TABLE_ROWS
|
TOTAL_MB
|
CREATE_OPTIONS
|
+--------------+---------------+------------+----------+----------------------------------------+
|
PS_8
|
test_compress
|
100000
|
19
|
row_format=压缩
KEY_BLOCK_SIZE=4
|
+--------------+---------------+------------+----------+----------------------------------------+
|
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
14
|
CentOS7-S2
PS_8
>
显示
创建
表格
test_compress
\
G
***************************
1.
行
***************************
表格
:
test_compress
创建
表格
:
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
无符号
不
零
,
`
identification_id
`
int
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
)
引擎=InnoDB
默认的
字符集=latin1
ROW_FORMAT=压缩
KEY_BLOCK_SIZE=4
1
行
在
集
(
0.01
证券交易委员会
)
|
到目前为止,一切都与MySQL 5.7相同:KEY_BLOCK_SIZE保留在整个表的定义中,而不是索引的定义中。
幸运的是,通过运行这个命令,我们有效地扭转了一切:
|
1
2
3.
|
CentOS7-S2
PS_8
>
改变
表格
test_compress
ROW_FORMAT=默认的
,
KEY_BLOCK_SIZE=0
,
算法=原地
,
锁=没有一个
;
查询
好吧
,
0
行
影响
(
2.56
证券交易委员会
)
记录
:
0
重复的
:
0
警告
:
0
|
|
1
2
3.
4
5
6
7
8
9
10
11
12
13
14
|
CentOS7-S2
PS_8
>
显示
创建
表格
test_compress
\
G
***************************
1.
行
***************************
表格
:
test_compress
创建
表格
:
创建
表格
`
test_compress
`
(
`
id
`
长整型数字
无符号
不
零
,
`
identification_id
`
int
无符号
默认的
零
,
`
时间戳
`
datetime
不
零
,
`
行动
`
varchar
(
50
)
不
零
,
`
结果
`
varchar
(
50
)
不
零
,
主要的
关键
(
`
id
`
)
,
关键
`
INDEX_test_compress_result
`
(
`
结果
`
)
,
关键
`
INDEX_test_compress_timestamp
`
(
`
时间戳
`
)
)
引擎=InnoDB
默认的
字符集=latin1
1
行
在
集
(
0.00
证券交易委员会
)
|
|
1
2
3.
4
5
6
|
CentOS7-S2
PS_8
>
选择
table_schema
,
table_name
,
table_rows
,
轮
(
data_length
/
1024
/
1024
)+轮
(
index_length
/
1024
/
1024
)+轮
(
data_free
/
1024
/
1024
)
TOTAL_MB
,
create_options
从
information_schema
.tables
在哪里
table_name=“test_compress”
;
+--------------+---------------+------------+----------+----------------+
|
TABLE_SCHEMA
|
TABLE_NAME
|
TABLE_ROWS
|
TOTAL_MB
|
CREATE_OPTIONS
|
+--------------+---------------+------------+----------+----------------+
|
PS_8
|
test_compress
|
100000
|
25
|
|
+--------------+---------------+------------+----------+----------------+
|
与往常一样,我们建议在生产环境中运行之前在开发环境中进行初步测试。
结论
在MySQL 5.7中,完全恢复(至少在表及其索引的定义中)的唯一方法是重新生成主键及其所有索引。这听起来像一个终端解决方案,但如果您使用mysqldump(我们总是建议使用rayben雷竞技 出于这些目的,它更快更有效),这是一个需要考虑的问题,因为在其定义中,它保留了那些错误的定义。幸运的是,这在MySQL 8中得到了修复。
很有趣,不是吗?







其他相关的MySQL错误:
这个问题在MySQL 8.0中看起来解决了,但是如果一个表以这种方式被改变了,那么升级一个安装会怎么样呢?
你好弗朗,
非常感谢你的评论。你能详细说明一下你的问题吗?你是在告诉我告诉客户端升级到MySQL 8,还是在告诉我如果我使用MySQL 5.7的修复,一段时间后我们迁移到MySQL 8,会发生什么,表的目标会发生什么。