c 添加mysql表单的一行数据类型,MySQL InnoDB表行格式及压缩

MySQL在创建表的时候定义表的性质(也叫表的类型),共有三种:静态表,动态表,压缩表。默认是静态表,如果存在varchar、blob、text字段,表类型就是动态了。除了表类型,另外一个参数:表行存储格式,这个主要用于InnoDB表引擎的相关数据组织和压缩,这是本文的主要内容。

1.静态表:

字段有固定长度,例如:char(20)。如果使用gbk字符集存储中文username,将占用40byte,如果username的实际内容没有达到 40byte,将会填充空格,以达到40byte。速度很快,因为mysql知道username总是从第41个字节开始,容易缓存,出现问题后也容易恢复(mysql知道记录的确切位置),需要更多的硬盘空间(如果有三个上面的字段,一条记录就会占120字节,即使实际只用了其中一部分)

2.动态表:

字段不定长(变长),这种表格式比较节省空间,但是复杂度更高,每条记录都有一个header,作用就是表明该记录有多长,所有的字符串列都是动态的(除非小于4个字节,这种情况下,节省的空间可以忽略不计,增加的复杂度会反而会导致性能丢失),通常占用比静态表少的多地空间,但是必须经常维护(避免碎片),例如:更新了用户名somebody为somebodyt,t不能立刻就出现在y的后面,因为空间被其他记录占用,对于出现碎片的列,每个新连接会损失6个字节。而且出现问题后不容易重建(前面我说的静态表正好相反)。

不包括连接的动态记录的空间消耗可以用下面的公式计算:

3+(列数+7)/8+(字符列数)+数字列的打包尺寸+字符串长度+(空列的数量+7)/8

每条记录的header可以表明那个字符串列是空的,那个数字列包含0(非空),在那种情况下不向磁盘存储,非空字符串包含一个长度字节加上字符串内容。

3.压缩表:

只读,使用很少的空间,用myisampack工具创建,表要小得多,每条记录分开压缩,所以不能同时访问,可以压缩静态表和动态表。创建方法:myisampack [options] filename

你大体上可以看出来,具体的计算空间不容易,只要根据不同的表特点选择数据库就可以了。上面的划分方法多适用于MyISAM存储引擎,对InnoDB引擎将在下文介绍。

InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

表压缩能提升性能,减少存储空间,主要是用在包含很多字符的表上,并且读要比写多的情况下,也就是在数据仓库的情况下应用居多,在使用表压缩的功能时候,innodb_file_per_table这个参数要启用,innodb_file_format这个参数设置成Barracuda。

ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8 ENGINE=InnoDB DEFAULT CHARSET=utf8;

可以使用innodb_compression_level这个参数来控制压缩率,mysql使用了LZ77算法来压缩数据。

In an InnoDB table, BLOB, VARCHAR, and TEXT columns that are not part of the primary key may be stored on separately allocated overflow pages. We refer to these columns as off-page columns. Their values are stored on singly-linked lists of overflow pages.

ROW_FORMAT [=] {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}

InnoDB表压缩

如何设置mysql innodb 表的压缩

第一,mysql的版本需要大于5.5

第二,设置innodb_file_format=barracuda

第三,create table或者alter talble 增加 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;(默认的key_block_size=16)根据经验,一般压缩比例可以达到30%-40%。

顺序不能改变,设置 innodb_file_format=barracuda,然后再建表或者修改表的compaesed。

使用row_format=compressed创建的表能使用比默认16KB更小的页,页的大小是参数key_block_size控制的。在创建压缩表之前,确认innodb_file_per_table配置启用了,innodb_file_format设置成了Barracuda。

对表启用压缩,需要在建表或alert table语句中使用ROW_FORMAT=COMPRESSED, KEY_BLOCK_SIZE从句。

CREATE TABLE freeoa

(c1 INT PRIMARY KEY)

ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;

如果指定了ROW_FORMAT=COMPRESSED,可以不指定key_block_size,默认的,innodb_page_size一半大小的页被使用。如果指定了key_block-size,可以忽略row_format=compressed参数,压缩也会自动启用。

key_block_size的值只能是小于或等于innodb_page_size,如果设置过大的话,会有告警,并忽略这个值,使用innodb_page_size的一半去设置。如何去决定key_block_size的大小,可以使用不同的值创建几个副本,对比ibd文件。key_block_size的大小应该大于记录大小的最大值,否则操作会失败,如果该值太小,插入和更新也许会导致耗时的解压操作,b-tree节点也许会更频繁的分裂,导致更大的数据文件和低效的索引。一般情况下key_block_size=8是个安全的设置。

key_block_size这个值决定了每个压缩chunk的大小,多少行能被打包到一个压缩页中。表上的索引也都使用相同的页大小来压缩。表压缩主要是用在表上的字符串字段比较多,数据的读比写更频繁的情况下,如果你的应用是io密集型的,不是cpu密集型的,那么压缩会带来很多性能的提升。

在innodb_file_format=antelope的情况下,建立压缩表(表结构中带有row_format=compressed),然后在设置innodb_file_format=barracuda ,此时建立的压缩表会忽略压缩参数。

Row_format: Compact //显示没有压缩

将系统变量(innodb_file_format)设置为Barracuda后,再建表:

| innodb_file_format       | Barracuda |

| innodb_file_format_check | ON        |

| innodb_file_format_max   | Antelope  |

再看表的状态:

Row_format: Compressed     //正确压缩

要将相关的更改写入配置文件,如果在重启之后,由于innodb_file_format参数被重新修改成antelope,导致后续写入的数据没有被压缩,虽然表结构中有row_format=compressed,但是不会起作用。在innodb_file_format=antelope的情况下,建立压缩表(表结构中带有row_format=compressed),然后在设置innodb_file_format=barracuda。其结果就是表结构中的row_format=compressed被忽略,后续写入表的数据并没有被压缩。另外看表的行格式是否被设定为支持压缩,要用'show table status like 'table''来看,不能只看表的定义(show create table)。

如innodb_file_format_check这参数所解释的,决定innodb是否会检查共享表空间中的表格式的tag,如果检查开启,那么当标记的表格式的tag高于innodb可以支撑的表格式,那么innodb会报错,并停止启动。如果支持,那么会将innodb_file_format_max的值改为这个tag的值。

文件格式 支持行格式 特性

Antelope

(Innodb-base) ROW_FORMAT=COMPACT

ROW_FORMAT=REDUNDANT Compact和redumdant的区别在就是在于首部的存存内容区别。

compact的存储格式为首部为一个非NULL的变长字段长度列表

redundant的存储格式为首部是一个字段长度偏移列表(每个字段占用的字节长度及其相应的位移)。

在Antelope中对于变长字段,低于768字节的,不会进行overflow page存储,某些情况下会减少结果集IO.

Barracuda

(innodb-plugin) ROW_FORMAT=DYNAMIC

ROW_FORMAT=COMPRESSED 这两者主要是功能上的区别功能上的。另外在行里的变长字段和Antelope的区别是只存20个字节,其它的overflow page存储。

另外这两都需要开启innodb_file_per_table=1

(这个特性对一些优化还是很有用的)

innodb_file_format参数

在innodb 1.0.6版本之前,innodb文件格式innodb_file_format只有Antelope(Antelope文件格式支持Redundant,Compact两种格式来存放行记录,Redundant是为了兼容之前版本而保留的。在mysql 5.1版本中,默认设置为Compact,用户可以通过show table status like 'table_name'来查看表使用的行格式row_format)。

从innodb 1.0.6开始引入了新的文件格式Barracuda ,在原来的基础上(Antelope)新增了Dynamic和Compressed两种行格式。Antelope是innodb-base的文件格式,Barracude是innodb-plugin后引入的文件格式,同时Barracude也支持Antelope文件格式。

Antelope(羚羊)是Built-in-InnoDB(MySQL内置的InnoDB)支持文件格式的代号,有两种"数据表格式"(row_format):Redundant(冗余)、Compact(紧凑)。

Barracuda(梭子鱼)是InnoDB Plugin支持的文件格式,在原来的基础上新增了两种数据表格式的支持:Dynamic和Compressed。

Compact和Redumdant的区别在就是在于首部的存存内容区别:

Compact的存储格式为首部为一个非NULL的变长字段长度列表。

Redumdant的存储格式为首部是一个字段长度偏移列表(每个字段占用的字节长度及其相应的位移)。

在Antelope中对于变长字段,低于768字节的,不会进行overflow page存储,某些情况下会减少结果集IO。

innodb_file_format使用

一般,innodb_file_format在配置文件中指定,row_format则在创建数据表时指定(Barracude也支持 old redundant and compact row formats):

CREATE TABLE freeoa (column1 INT PRIMARY KEY) ENGINE=InnoDB ROW_FORMAT=Compressed KEY_BLOCK_SIZE=8;

在全局会话中设置:

SET GLOBAL innodb_file_per_table=1

SET GLOBAL innodb_file_format=Barracuda;

SET GLOBAL innodb_file_format_max=Barracuda;

在指定innodb_file_format = Barracuda时,建议配合如下参数一起使用:

innodb_strict_mode = 1 #建议加上

innodb_file_format=Barracuda

innodb_file_format_max=Barracuda

innodb_file_per_table = 1

因为system tablespace使用的是Antelope文件格式,如果不指定innodb_file_per_table = 1(5.6.6是默认开启的),那么innodb表被存储在system tablespace,这时在建表的时候无法使用Dynamic和Compressed两种行格式(如果设置了innodb_strict_mode = 1,那么建表的时候指定Dynamic和Compressed会直接报错。如果没有指定innodb_strict_mode = 0,建表的时候指定Dynamic和Compressed会被忽略,默认设置为Compact)。

Recommends enabling innodb_strict_mode when using ROW_FORMAT and KEY_BLOCK_SIZE clauses on CREATE TABLE, ALTER TABLE, and CREATE INDEX statements. When innodb_strict_mode is OFF, InnoDB ignores conflicting clauses and creates the table or index, with only a warning in the message log. The resulting table might have different behavior than you intended, such as having no compression when you tried to create a compressed table. When innodb_strict_mode is ON, such problems generate an immediate error and the table or index is not created, avoiding a troubleshooting session later.

文件格式兼容性检查

InnoDB Plugin引入的新的文件格式,也引入较为完整的文件兼容性检查,以防止误操作非兼容的文件格式。兼容性检查一共有三类:启动数据库时、创建数据表时、访问数据表时。

当数据库启动时候,参数innodb_file_format_check(>=5.1.38)会要求InnoDB在启动时检查当前数据表的格式。设置为ON时,如果检测到不支持的格式,那么InnoDB会启动失败;设置为OFF时,检测到不支持的仅会给出警告,并不会导致启动失败。

当创建数据表时,InnoDB会依据参数innodb_file_format进行检查,如果创建的数据表格式高于innodb_file_format,则创建会失败。

当访问某个数据表(table-access)时,InnoDB也会进行兼容性检查。只要当前运行的InnoDB版本能够支持的格式,都能够被访问,无论参数innodb_file_format的配置。

把innodb_file_format_check设置为OFF是很危险的。在InnoDB启动后,一般需要做一些恢复工作,例如Double write buffer/Insert buffer中的数据处理(这依赖于innodb_fast_shutdown参数),试想如果成功启动,但是某些表是不支持的格式,但是InnoDB仍然安装旧版本做恢复,这可能会毁掉相关数据。所以,建议innodb_file_format_check设置为ON。如果是OFF,关闭InnoDB的innodb_fast_shutdown参数请务必设置成0。

MyISAM和InnoDB的行格式

InnoDB存储引擎和大多数数据库一样,记录是以行的形式存储的。这意味着页中保存着表中一行行的数据。到MySQL 5.1时,InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant是为兼容之前版本而保留的,如果你阅读过InnoDB的源代码,会发现源代码中是用PHYSICAL RECORD(NEW STYLE)和PHYSICAL RECORD(OLD STYLE)来区分两种格式的。MySQL 5.1默认保存为Compact行格式。你可以通过命令SHOW TABLE STATUS LIKE 'table_name'来查看当前表使用的行格式,其中row_format就代表了当前使用的行记录结构类型。

MyISAM行存储

MyISAM有3种行存储格式:fixed、dynamic、compressed。

其中fixed为默认格式,只有当表不包含变长字段(varchar,varbinary,blob,text)时使用,该每行都是固定的,所以很容易获取行在页上的具体位置,存取效率比较高,但是占用磁盘空间较多;

dynamic

每行都有一个行头部,包含bitmap,用以记录那些列为空(NULL列不算为空);

相比于fixed,其有如下特性:

所有字符串列都是动态存储的,除非长度小于4;

字符类型若长度为0/数字类型为0都会不占用存储空间,由bitmap标注,NULL值不包含在内;

如果要update行,其扩展后很容易导致行链接既而产生碎片,一旦crash若link丢失则比较难恢复,fixed模式update不会产生碎片;

compressed只能通过myisampack创建且为只读。上文已有介绍。

MyISAM的索引文件包含一个flag记录基表是否正常关闭,如果mysqld启动时指定了--myisam-recover-options,则在打开表时检测并自动修复表。

InnoDB行存储

Innodb plugin新引入Barracuda(梭子鱼),其包含compressed/dynamic两种行格式,而之前的compact/redundant统属于antelope(羚羊);

Barracuda VS Antelope

由innodb_file_format(动态)参数决定,目前可选值由Antelope和Barracuda,默认为前者;要想要此参数生效需要做一番调整,因为共享表空间默认为Antelope,因此要想使用Barracuda为默认值,还必须先声明innodb_file_per_table。innodb_file_format用于控制行格式,全局变量可动态调整,5.5默认依旧是Antelope。我们行来看Antelope格式

Redundant行结构

字段长度偏移列表|记录头信息|列1数据|列2数据

Redundant是MySQL 5.0版本之前InnoDB的行记录存储方式,MySQL 5.0支持Redundant是为了向前兼容性。Redundant行头部为字段长度偏移信息,包括变长和非变长的, 还包含了3个隐藏列:RowID(没有主键时使用)/Transaction ID/Roll Point; 而compact只包含变长的,节约了空间;

冗余行格式没有NULL标志位;对于redundant格式,varchar为Null时不占用空间,但是char为NULL需要占用空间,因为其没有Null标志位;

记录头信息占用6个字节,比compact多1字节;

对于定长char,若为NULL依旧填充整个字段,而varchar为Null时不占用空间;

记录头信息,与compact相比,多了黑体字部分,缺失record_type。

名称长度bit功能

Deleted_flag1是否被删除

Min_rec_flag11则表示该记录为预先被定义的最小记录

N_owned4该记录拥有的总记录数

Heap_no13索引中该行的排序记录

N_fields10记录中列数量

1byte_offs_flag1偏移量列表是1字节还是2字节

Next_recorder16下一条记录相对位置

()1未知

()1未知

当列的长度小于255字节,用1字节表示;若大于255个字节,用2个字节表示。第二个部分为记录头信息(record header),不同于Compact行格式,Redundant行格式固定占用6个字节(48位),每位的含义见表。从表中可以看到,n_fields值代表一行中列的数量,占用10位,这也很好地解释了为什么MySQL一个行支持最多的列为1023。另一个需要注意的值为1byte_offs_flags,该值定义了偏移列表占用1个字节还是2个字节。最后的部分就是实际存储的每个列的数据了。

可以使用hexdump –C –v test.idb查看其二进制代码。

Compact行格式

字段长度偏移列表|NULL标志位|记录头信息|列1数据|列2数据

Compact行记录是在MySQL 5.0时被引入的,其设计目标是能高效存放数据。简单来说,如果一个页中存放的行数据越多,其性能就越高。引入行头存放该行内变长字段的length,当列小于255字节时占用1个字节,大于255而小于65535时占用2个字节;故varchar最大长度为2的16次方-1;

第2个指示该行是否有NULL值,占用1字节;NULL列不占用数据存储空间;

记录头信息:5个字节共计40bit,用于链接相邻的记录案的行级锁。

名称长度bit功能

Deleted_flag1是否被删除

Min_rec_flag11则表示该记录为预先被定义的最小记录

N_owned4该记录拥有的总记录数

Heap_no13索引中该行的排序记录

Record_type3行类型0=普通 1=B+节点指针

Next_recorder16下一条记录相对位置

()1未知

()1未知

除此之外,每页还有两个隐含字段:

DB_TRX_ID:6字节,记录最近的一个事务标示符

DB_ROLL_ID:7字节,指向回滚日志记录

注:对于redundant格式,varchar为Null时同样不占用空间,但是char为NULL需要占用空间,因为其没有Null标志位。

行溢出

Innodb表为IOT,采用了B+数类型,故每个页面至少要存储2行数据,如果行过大则会产生行溢出;

理论上mysql的varchar可存储65525字节,强于oracle的4000,但对于InnoDB其实际上限为65532,且该值为表所有varchar列长度总和;对于utf8字符集,一个字符占3个字节,则其上限又缩小为1/3;

如果强行创建varchar(65535)的字段,在sql_mode不为restricted的情况下,其会被隐式转换为mediumtext;

不论是varchar还是blob/text,只要保证一个16k的页面能容下2行数据,应该不会行溢出;

而一旦行溢出,字段前768字节依旧存放于当前页面,数据一般使用B-tree Node页,而溢出的行存放于Uncompress Blob页;

而barracuda采用了完全行溢出,即只保留字段的前20字节。

Compressed与Dynamic行记录格式

InnoDB Plugin引入了新的文件格式(file format,可以理解为新版本页格式),对于以前支持的Compact和Redundant格式将其称为Antelope文件格式,新的文件格式称为Barracuda。Barracuda文件格式下拥有两种新的行记录格式Compressed和Dynamic两种。新的两种格式对于存放BLOB的数据采用了完全的行溢出的方式,在数据页中只存放20个字节的指针,实际的数据都存放在BLOB Page中,而之前的Compact和Redundant两种格式会存放768个前缀字节。

下图是Barracuda文件格式的溢出行:

724bd839a8473a2633948de8e31d30bd.png

Compressed行记录格式的另一个功能就是,存储在其中的行数据会以zlib的算法进行压缩,因此对于BLOB、TEXT、VARCHAR这类大长度类型的数据能进行非常有效的存储。

在使用过程中遇到的一些问题:

从5.1采用in-place的方式升级到5.6时,在操作innodb表时会有警告报出:

MySQL [freeoa]> create index idx_company_uuid on company(uuid);

Query OK, 0 rows affected, 2 warnings (0.15 sec)

Records: 0  Duplicates: 0  Warnings: 2

MySQL [freeoa]> show warnings;

+---------+------+--------------------------------------------------------------------+

| Level   | Code | Message                                                            |

+---------+------+--------------------------------------------------------------------+

| Warning | 1478 | InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. |

| Warning | 1478 | InnoDB: assuming ROW_FORMAT=COMPACT.                               |

+---------+------+--------------------------------------------------------------------+

MySQL [freeoa]> show warnings;

+---------+------+-------------------------------------------------------------------------------------+

| Level   | Code | Message                                                                             |

+---------+------+-------------------------------------------------------------------------------------+

| Note    | 1880 | TIME/TIMESTAMP/DATETIME columns of old format have been upgraded to the new format. |

| Warning | 1478 | InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.                  |

| Warning | 1478 | InnoDB: assuming ROW_FORMAT=COMPACT.                                                |

| Warning | 1478 | InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.                  |

| Warning | 1478 | InnoDB: assuming ROW_FORMAT=COMPACT.                                                |

| Warning | 1478 | InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.                  |

| Warning | 1478 | InnoDB: assuming ROW_FORMAT=COMPACT.                                                |

+---------+------+-------------------------------------------------------------------------------------+

在使用JDBC通过应用程序向数据库插入数据的时候,我的表中类型为text的属性如果导入过长的数据,则会报错:

MySQL: Error Code: 1118 Row size too large (> 8126). Changing some columns to TEXT or BLOB

解决办法如下:

SET GLOBAL innodb_file_format='Barracuda';

alter table yourTable ROW_FORMAT=COMPRESSED

即可成功导入数据。

如果不设定第一行代码就执行第二行代码给出警告:

0 row(s) affected, 2 warning(s): 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope.

1478 InnoDB: assuming ROW_FORMAT=COMPACT.

所以必须先执行第一行代码。

原表:

show create table keyword\G

ROW_FORMAT=DYNAMIC

show table status like 'keyword'\G

Row_format: Dynamic

Create_options: row_format=DYNAMIC

在操作很大表时有报错:

mysql> alter table warning_freeoa_search ROW_FORMAT=Compressed KEY_BLOCK_SIZE=16;

ERROR 1799 (HY000): Creating index 'PRIMARY' required more than 'innodb_online_alter_log_max_size' bytes of modification log. Please try again.

InnoDB的MVCC

多版本并发控制算法,多版本并发控制Multiversion Concurrency Controll(MVCC)。

隐式和显式锁

InnoDB在开启事务时,获取隐式锁,在事务提交或者回滚时释放锁,InnoDB根据隔离级别在需要的时候自动加锁。

但InnoDB也支持显式锁:

SELECT ... FOR UPDATE

SELECT ... LOCK IN SHARE MODE

这是在服务器层实现的,和存储引擎无关。本书建议除了禁用了AUTOCOMMIT,可以使用LOCK_TABLES之外,其他任何时候都不要显示地执行LOCK TABLES,不管使用的是什么存储引擎。

关于MVCC

第一点:

MVCC并不是MySql独有的,Oracle,PostgreSQL等都在使用。

MVCC并没有简单地使用行锁,而是使用“行级别锁”row-level locking。

MVCC的基本实现原理是:通过保存数据在某个时间点的快照来实现的。这意味着一个事务无论运行多长时间,在同一个事务里能够看到数据一致的视图。根据事务开始的时间不同,同时也意味着在同一个时刻不同事务看到的相同表里的数据可能是不同的。

MVCC的基本特征:

每行数据都存在一个版本,每次数据更新时都更新该版本。

修改时Copy出当前版本随意修改,各个事务之间无干扰。

保存时比较版本号,如果成功commit,则覆盖原记录;失败则放弃rollback。

InnoDB存储引擎MVCC的实现策略:

在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号可能为空。这里的版本号并不是实际的时间值,而是系统版本号。每开始 个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。

每个事务又有自己的版本号,这样事务内执行CRUD操作时,就通过版本号的比较来达到数据版本控制的目的。

MVCC具体的操作如下:

SELECT:InnoDB会根据以下两个条件检查每行记录:

1、InnoDB只查找版本早于当前事务版本的数据行也就是,行的系统版本号小于或等于事务的系统版本号,这样可以确保事务读取的行,只么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。

2、行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。

只有1和2同时满足的记录,才能做为查询结果。

INSERT:InnoDB为新插入的每一行保存当前系统版本号作为行版本号。

DELETE:InnoDB为删除的每一行保存当前系统版本号作为行删除标识。

UPDATE:InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当系统的版本号为原来的行作为删除标识。

保存这两个额外系统版本号,使大多数操作都可以不用加锁。这样设计使得计数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

MVCC只在REPEATABLE READ和READ COMMITED两个隔离级别下工作,其它两个隔离级别和MVCC不兼容。

Innodb的实现算不上MVCC,因为并没有实现核心的多版本共存,undo log中的内容只是串行化的结果,记录了多个事务的过程,不属于多版本共存。但理想的MVCC是难以实现的,当事务仅修改一行记录使用理想的MVCC模式是没有问题的,可以通过比较版本号进行回滚;但当事务影响到多行数据时,理想的MVCC据无能为力了。

比如,如果Transaciton1执行理想的MVCC,修改Row1成功,而修改Row2失败,此时需要回滚Row1,但因为Row1没有被锁定,其数据可能又被Transaction2所修改,如果此时回滚Row1的内容,则会破坏Transaction2的修改结果,导致Transaction2违反ACID。

理想MVCC难以实现的根本原因在于企图通过乐观锁代替二段提交。修改两行数据,但为了保证其一致性,与修改两个分布式系统中的数据并无区别,而二段提交是目前这种场景保证一致性的唯一手段。二段提交的本质是锁定,乐观锁的本质是消除锁定,二者矛盾,故理想的MVCC难以真正在实际中被应用,Innodb只是借了MVCC这个名字,提供了读的非阻塞而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值