InnoDB(三):InnoDB表的逻辑和物理存储

1. InnoDB逻辑存储结构

2. InnoDB行记录格式

3. InnoDB数据页结构

4. 约束

5. 视图

6. 分区表


1. InnoDB逻辑存储结构

    所有的数据都被放在一个空间中,这个空间称为表空间(table space),表空间又由段(segmet)、区(extent)和页(page)组成,如下图所示。

(1)表空间(table space)

    表空间是存储引擎的最高层,所有的数据都存放在表空间中。表空间可以看做一个逻辑概念,InnoDB 把数据保存在表空间,本质上是一个或多个磁盘文件组成的虚拟文件系统。如果没有开启innodb_file_per_table,则所有数据都存放在默认的共享表空间中,如果开启这个参数,那么,每张表的数据可以单独放到一个表空间中。表空间就是存放表的地方,它可以是一个物理文件,也可以是多个物理文件的集合,可以通过参数innodb_data_file_path进行设置。

(2)段(segment)

    由于InnoDB存粗引擎是索引组织的,因此数据即索引,索引即数据。B+树的叶子节点即为数据段,B+树的非叶子节点即为索引段,除了数据段和索引段之外,表空间还包含回滚段。

(3)区(extent)

    一个段通常由多个区组成,每个区大小固定为1MB,为了保证页的连续性,InnoDB存储引擎一次从磁盘申请4~5个区。表空间增长时,表空间会按连续64个页的大小开始增长。

(4)页(page)

    区由页组成,默认情况下,InnoDB存储引擎的页大小为16KB,因此一个区由64个连续的页组成,页是InnoDB磁盘管理的最小单位。

    InnoDB1.0.x版本引入了压缩页,即每个页的大小可以通过参数KEY_BLOCK_SIZE设置为2K、4K、8K,因此每个区对应页的数量就应该为512、256、128.

    InnoDB1.2.x版本新增了参数innodb_page_size,通过该参数可以将默认页的大小设置为4K,8K,但是页中的数据是不压缩的,这时区的数量同样也为256,128,总之,不论页的大小怎么变化,区的大小总是为1MB。

    在InnoDB存储引擎中,常见的页类型有:

  • 数据页
  • undo页
  • 系统页
  • 事务数据页
  • 插入缓冲位图页
  • 插入缓冲空闲列表页
  • 未压缩的二进制大对象页
  • 压缩的二进制大对象页

(5)行(row)

     InnoDB的数据是按行进行存储的,每个页存放的行记录也是有硬性规定的,最多允许存放16K/2 - 200 = 7992行记录。

2. InnoDB行记录格式

    InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant格式是为兼容之前的版本而保留的,在MySQL5.1 版本中,默认设置为Compact行格式。

2.1 Compact行记录格式

    Compact行记录是在MySQL5.0引入的,其设计的目的是高效的存储数据,它的存储方式如下图所示:

  • 行记录首部是一个非NULL变长字段长度列表,并且是按照列的顺序逆序放置的,其长度为:1)若列的长度小于255字节,用1字节表示;2)若大于255字节,用2字节表示。变长字段的长度最大不超过2字节,这时因为MySQL数据库中VARCHAR类型的最大长度限制为65535
  • NULL标志位指示了该行数据中是否有NULL值,有则用1表示,该部分所占的字节应该为1字节。
  • 记录头信息固定用5字节(40位),每位的含义如下:
名称大小(bit)描述
()1未知
()1未知
deleted_flag1该行是否已经被删除
min_rec_flag1为1,如果该记录是预先被定义为最小的记录
n_owned4该记录拥有的记录数
heap_no13索引堆中该条记录的排序记录
record_type3记录类型,000表示普通,001表示B+树节点指针,010表示Infimun,011表示Supremun,1xx表示保留
next_record16页中下一条记录的相对位置
Total40
  •  对于实际每列的数据,需要特别注意的是,NULL不占该部分任何空间,即NULL除了占有NULL标志位,实际存储不占有任何空间。
  • 每行数据除了用户定义的列外,还有两个隐藏列,分别是事务ID列回滚指针列,分别为6字节和7字节大小,如果InnoDB没有定义主键,每行还会增加一个6字节的rowid列
  • 不管是CHAR型还是VARCHAR型,在compact格式下NULL值都不占任何存储空间。固定长度CHAR字段在未能完全占用其长度空间时,会用0x20来进行填充。

2.2 Redundant行记录格式

    Redundant是MySQL 5.0版本之前的行记录存储方式,它的行记录存储格式如下:

  •  字段长度偏移列表同样是按照列的顺序逆序放置的,若列的长度小于255字节,用1字节表示,若大于255字节,用2字节表示。
  • 记录头信息占用6字节(48bit),每位的含义如下表所示:
名称大小(bit)描述
()1未知
()1未知
deleted_flag1该行是否已被删除
min_rec_flag1为1,如果该记录是预先被定义为最小的记录
n_owned4该记录拥有的记录数
heap_no13索引堆中该记录的索引号
n_fileds10记录中列的数量,一行最多支持的列为1023
1byte_offs_flag1偏移列表为1字节还是2字节
next_record16页中下一条记录的相对位置
total48
  • 每行数据除了用户定义的列外,还有两个隐藏列,分别是事务ID列回滚指针列,分别为6字节和7字节大小,如果InnoDB没有定义主键,每行还会增加一个6字节的rowid列
  • 对于VARCHAR型NULL值,在Redundant格式下NULL值都不占任何存储空间,而CHAR型的NULL值需要占用空间。固定长度CHAR字段在未能完全占用其长度空间时,会用0x20来进行填充,CHAR型在不同的字符集下,会占用可能存放的最大字节数。

2.3 行溢出数据

    BLOB可以不将数据存放在溢出页面,而且即便是VARCHAR列类型数据,依然有可能被存放为行溢出数据:

(1)VARCHAR类型行溢出数据

    MySQL数据库的VARCHAR类型可以存放65535字节,但是有没有想过,InnoDB存储引擎的页为16KB,即16384字节,怎么能存放65535字节呢 ? 因此,在一般情况下,InnoDB存储引擎的数据都是存放在页类型为B-tree node中,但当发生行溢出时,数据存放在页类型为Uncompress BLOB中。如下图所示:

    那多长的VARCHAR是保存在单个数据页中,从多长开始又回保存在BLOB页呢 ? 由于InnoDB是B+树结构,这样每个页中至少应该有两条行记录,因此如果页中只能存放下一条记录,那个InnoDB会自动将行数据存到溢出页中。 

(2)TEXT或BLOB类型行溢出数据

    对于Text或Blob的数据类型,是放在数据页中还是放在BLOB页中呢,这个和前面讨论的VARCHAR一样,至少保证一个页能存放两条记录。

2.4 Compressed和Dynamic行记录格式

    InnoDB1.0.x版本开始引入了新的文件格式,以前支持的Compact和Redundant格式称为antelope文件格式,新的文件格式称为Barracuda文件格式,该文件格式拥有两种新的行记录格式:Compressed和Dynamic。为了解决不同版本下页结构兼容性问题,新的文件格式总是包含之前版本的页格式,如下图所示:

    参数innodb_file_format用来指定文件格式,参数innodb_file_format_check用来检测当前InnoDB存储引擎文件格式的支持度,该值默认为ON。 

    两种新的文件格式对于存放BLOB中的数据采用了完全的行溢出的方式,在数据页中只存放20个字节的指针,实际的数据都存放在Off Page中,之前的Compact和Redundant两种格式会存放768个前缀字节。

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

2.5 CHAR行结构存储

    MySQL4.1版本开始,CHA(N)中的N指的是字符的长度,而不是之前版本的字节长度,也就是说,在不同的字符集下,CHAR类型列内部存储的可能不是定长的数据。例如,对于UTF-8下CHAR(10)类型的列,其最小可以存储10字节的字符,而最大可以存储30字节的字符。因此,对于多字节字符编码的CHAR数据类型的存储,InnoDB存储引擎在内部将其视为变长字符类型,这也就意味着,在变长长度列表中会记录CHAR数据类型的长度。因此可以说,在多字节字符集的情况下,CHAR和VARCHAR的实际行存储基本是没有区别的。

3. InnoDB数据页结构

    InnoDB数据页由以下7个部门组成,如下图所示:

     其中File Header、Page Header、File Trailer的大小是固定的,分别是38,56,8字节,这些空间用来标记该页的一些信息,如Checksum,数据页所在B+树索引的层数等。User Records、Free Space、Page Directory这些部分为实际行记录存储空间,因此大小是动态的。

3.1 File Header

    File Header(文件头)用来记录页的一些头信息,由8个部分组成,共占用38字节,如下表所示:

名称大小(字节)说明
FIL_PAGE_SPACE_CHECKSUM4    当MySQL为4.0.14之前的版本时,该值为0。在之后的版本中,该值代表页的checksum值
FIL_PAGE_OFFSET4    表空间中页的偏移值,如某独立表空间a.ibd的大小为1G,如果页的大小为16KB,那么总共有65536个页。FIL_PAGE_OFFSET表示该页在所有页中的位置。若此表空间的ID为10,那么搜索页(10,1)就表示查找表a中的第二个页。
FIL_PAGE_PREV4    当前页的上一个页,B+树特性决定叶子节点必须是双向链表。
FIL_PAGE_NEXT4   当前页的下一个页,B+树决定叶子节点必须是双向链表。
FIL_PAGE_LSN8    该值代表页最后被修改的日志序列位置LSN
FIL_PAGE_TYPE2    InnoDB存储引擎的页类型,0x45BF代表了存放的是数据页,即实际行记录的存储空间。
FIL_PAGE_FILE_FLUSH_LSN8    该值仅在系统表空间的一个页中定义,代表文件至少被更新到了该LSN值,对于独立表空间,该值都为0。
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID4    从MySQL4.1开始,该值代表页属于哪个表空间。

3.2 Page Header

    Page Header(页头)用来记录数据页的状态信息,由14个部分组成,共占用56个字节,如下表所示:

名称大小(字节)说明
PAGE_N_DIR_SLOTS2  在Page Directory(页目录)中Slot数
PAGE_HEAP_TOP2  堆中第一个记录的指针,记录在页中是根据堆的形式存放的
PAGE_N_HEAP2  堆中的记录数,一共占2字节,但是第15位表示行记录格式
PAGE_FREE2  指向可重用空间的首指针
PAGE_GARBAGE2  已删除记录的字节数,即行记录结构中delete flag为1的记录大小总数
PAGE_LAST_INSERT2  最后插入记录的位置。
PAGE_DIRECTION2

  最后插入的方向。可能的取值为:

  • PAGE_LEFT(0x01)
  • PAGE_RIGHT(0x02)
  • PAGE_SAME_REC(0x03)
  • PAGE_SAME_PAGE(0x04)
  • PAGE_NO_DIRECTORY(0x05)
PAGE_N_DIRECTION2  一个方向连续插入记录的数量
PAGE_N_RECS2  该页中记录的数量
PAGE_MAX_TRX_ID8  修改当前页的最大事务ID,注意该值仅在Secondary Index中定义
PAGE_LEVEL2  当前页在索引树中的位置,0x00代表叶节点,即叶节点总是在第0层
PAGE_INDEX_ID8  索引ID,表示当前页属于哪个索引
PAGE_BTR_SEG_LEAF10  B+树数据页非叶节点所在段segment header,注意该值仅在B+树的Root页中定义
PAGE_BTR_SEG_TOP10  B+树数据页所在段的segment header,注意该值仅在B+树的Root页中定义。

3.3 Infimun和Supremum Records

  在InnoDB存储引擎中,每个数据页中有两个虚拟的行记录,用来限定记录的边界。Infimum记录是比该页中任何主键都要小的值,Supremum指比任何可能大的值还要大的值。这两个值在页创建时被建立,并且在任何情况下不会被删除。如下图所示:

3.4 User Records

    User Record为实际存储行记录的内容,InnoDB存储引擎总是B+树索引组织的。

3.5 Free Space

    Free Space就是空闲空间,同样也是个链表数据结构,在一条记录被删除后,该空间会被加入到空闲链表中。

3.6 Page Directory

  Page Directory即页目录,页中查找记录时,会先查这个Page Directory,然后再去找记录。页目录中存放了记录的相对位置,有些时候这些记录称为Slots(槽)或者Directory Slots(目录槽)。InnoDB并不是每个记录拥有一个槽,InnoDB存储引擎的槽是一个稀疏目录,即一个槽中可能包含多条记录,当记录被插入或者删除时需要对槽进行分裂或平衡的维护操作。

  由于Page Directory是稀疏目录,二叉查找的结果只是一个粗略的结果,因此必须通过recorder header中的next record来继续查找相关记录。需要注意的是,B+树索引本身并不能找到一条具体的记录,能找到的只是该记录所在的页,数据库把页载入内存中,然后通过Page Directory进行二叉查找,只不过二叉查找的时间复杂度很低,同时在内存中查找很快,因此通常忽略这部分查找所用的时间。

3.7 File Trailer

  File Trailer中只有一个FIL_PAGE_END_LSN部分,占用8字节,前4字节代表该页的checksum值,最后4字节和File Header中的FIL_PAGE_LSN相同。默认配置下,InnoDB存储引擎每次从磁盘读取一个页就会检测该页的完整性,即页是否发生Corrypt,这就是通过File Trailer部分进行检测,而该部分的检测会有一定的开销,用户可以通过参数innodb_checksums来开启或关闭对这个页完整性检查。

  MySQL5.6.6开始新增参数innodb_checksum_algorithm,该参数用于控制检测checksum函数的算法,默认为crc32。

4. 约束

4.1 数据完整性

    一般来说,数据完整性有以下三种形式:

  • 实体完整性:保证表中有一个主键,用户可以通过定义Primary Key或Unique Key约束来保证实体的完整性;
  • 域完整性:保证数据每列的值满足特定的条件,域完整性可以通过:1)选择合适的数据类型;2)外键约束;3)编写触发器;4)DEFAULT约束等途径来保证;
  • 参照完整性:保证两张表之间的关系,可以通过定义外键以强制参照完整性,也可以通过编写触发器强制执行。

4.2 约束的创建和查找

    对于InnoDB存储引擎,提供了以下几种约束:

  • Primary Key
  • Unique Key
  • Foreign Key
  • Default
  • NOT NULL

    约束的创建可以采用以下两种方式:

  (1)表建立时就进行约束定义;

  (2)利用ALTER TABLE命令来进行创建约束;

    对于Unique Key的约束,用户还可以通过命令CREATE UNIQUE INDEX来建立。对于主键约束而言,其默认约束名为PRIMARY,对于Unique Key约束而言,默认约束名和列名一样,当然也可以指定Unique Key约束的名字。而Foreign Key的名字,默认名称比较特殊。

4.3 错误数据的约束

    在某些默认情况下,MySQL数据库允许非法或者不正确的数据的插入或更新,又或者可以在数据库内部将其转化为一个合法值。比如向NOT NULL字段插入一个NULL值,MySQL会将其更改为0再进行插入,因此数据库本身没有对数据进行正确性约束。

    如果用户想通过约束对于数据库非法数据的插入和更新,那么用户必须设置参数sql_mode,用来严格审核输入的参数,比如:

> set sql_mode = 'STRICT_TRANS_TABLES';

4.4 ENUM和SET约束

  Mysql不支持传统的CHECK约束,但是通过ENUM和SET类型可以解决部分这样的约束需求。例如一个表上有一个性别类型,规定域的范围只能是male或female,这种情况下可以通过ENUM类型来进行约束:

create table(
    id int,
    sex ENUM('male', 'female')    
);

    ENUM和SET只能对离散值进行约束,但是对于传统的CHECK约束支持的连续值的范围约束或者更复杂的约束无能为力,这时需要通过触发器来实现对于值域的约束。 

4.5 触发器

    触发器的作用是在执行INSERT、DELETE和UPDATE命令之前或者之后自动调用SQL命令或者存储过程,创建触发器的命令是CREATE TRIGGER,只有具备Super权限的MuSQL数据库用户才可以执行这条命令。

  最多可以为一个表建立6个触发器,即分别为INSERT、UPDATE、DELETE的BEFORE和AFTER各定义一个。BEFORE和AFTER代表触发器发生的时间,表示是在每行操作的之前发生还是之后发生。

  通过触发器,用户可以实现MySQL数据库本身不支持的一些特性,例如对传统的CHECK约束的支持,物化视图,高级复制,审计等特性。

4.6 外键约束

  外键约束用来保证参照完整性,MyISAM引擎不支持外键,而InnoDB存储引擎则完整支持外键的约束。外键的定义如下:

[constraint [symbol]] foreign key
[index_name] (index_col_name, ...)
references tbl_name(index_col_name, ...)
[on delete reference_option]
[on update reference_option]

reference_option:
RESTRICT | CASCADE | SET NULL | NO ACTION

  一般来说,称被引用的表为父表,引用的表为子表,外键定义时的on delete和on update表示在对父表进行delete和update操作时,对子表所做的操作,可定义的子表操作有:

(1)cascade:表示当父表发生delete或者update操作时,对相应子表中的数据也进行delete或者update操作;

(2)set null:表示当父表发生delete或者update操作时,对相应子表中的数据被更新为NULL值,但是子表中的相应列必须允许为NULL值;

(3)no action:表示当父表发生delete或者update操作时,抛出错误,不允许这类操作发生;

(4) restrict:表示当父表发生delete或者update操作时,抛出错误,不允许这类操作发生,如果没有指定on delete或者on update,restrict就是默认的外键设置。

  对于参照完整性约束,外键能起到一个非常好的作用,但是对于数据库的导入操作,外键往往导致在外键约束的检查上花费大量时间。但是用户可以在导入过程中忽视外键的检查:

> set foreign_key_checks = 0;
> load data...
> set foreign_key_checks = 1;

5. 视图

    视图是一个命名的虚表,可以当作表来使用,与持久表不同的是,视图中的数据没有实际的物理存储。

5.1 视图的作用

    视图的主要作用之一是被用来做一个抽象装置,特别是一些应用程序,程序本身不需要关心基表的结构,只需要按照视图定义来取数据或者更新数据,因此视图同时在一定程度上起到一个安全层的作用。MySQL 5.0开始支持视图,创建视图的语法为:

[or replace]
[algorithm = {undefined | merge | temptable}]
[definer = {user | current_user}]
[sql securiy {definer | invoker}]
view view_name [(column_list)]
as select_statement
[with [cascaded | local] check option]

    用户可以对某些视图进行更新操作,其本质就是通过视图的定义来更新基本表,一般称可以进行更新操作的视图为可更新视图,视图定义中的WITH_CHECK OPTION就是针对于可更新的视图的,即更新值是否需要检查。

    命令SHOW TABLES会显示出当前数据库下所有的表,但是因为视图是虚表,同样也被作为表显示出来。  

5.2 物化视图

  Oracle支持物化视图,即该视图不是基于基表的虚表,而是根据基表实际存在的实表。物化视图可以用于预先计算并保存多表的链接(JOIN)或聚集(GROUP BY)等耗时较多的SQL操作结果,这样在执行复杂查询时,就可以避免进行这些耗时的操作。

  MySQL并不支持物化视图,不过通过触发器,MySQL可以实现类似物化视图的功能。

6. 分区表

    分区功能不是在存储引擎层完成的,因此不是只有InnoDB存储引擎才支持分区,常见的存储引擎MyISAM、NDB等都支持。分区的过程是将一个表或者索引分解为多个更小、更可管理的部分。就访问数据库而言,从逻辑上讲,只有一个表或索引,但是在物理上这个表或索引可能由数十个物理分区组成,每个分区都是独立的对象,可以独自处理。

    MySQL数据库支持的分区类型为水平分区,即将一个表的不同行记录分配到不同的物理文件中,并不支持垂直分区。此外,MySQL数据库的分区是局部分区索引,一个分区既存放了数据又存放了索引,而全局分区指,数据存放在各个分区中,但是所有数据的索引放在一个对象中,目前MySQL不支持全局分区。

   不论创建何种类型的分区,如果表中存在主键或者唯一索引时,分区列必须是唯一索引的一个组成部分。为什么呢 ? // todo

6.1 RANGE分区

    行数据基于属于一个给定区间的列值被放入分区。例如,当di小于10时,数据插入p0分区,当id大于等于10小于20时,数据插入p1分区:

create table t(
    id int
)engine = inndb
partition by range(id)(
partition p0 values less than (10),
partition p1 values less than (20),
partition p2 values less than maxvalue
);

  range分区主要用于日期列的分区,例如对于销售类的表,可以根据年来区分存放销售记录。创建分区后,如果要删除某一年的数据,只需要删除该年所在的分区即可,此外,如果只查询某年的数据,只需要取搜索指定的分区,不会搜索所有分区,极大提升了查询速度。 

6.2 LIST分区

  list分区和range分区非常相似,只是分区列的值是离散的,而非连续的。例如:

create table t(
    a int,
    b int
)engine = innodb
partition by list(b)(
partition p0 values in (1, 3, 5, 7, 9),
partition p1 values in (0, 2, 4, 6, 8)
);

    不同于range分区中定义的values less than语句,list分区使用values in,因为每个分区的值是离散的,因此只能定义值。此外,在使用insert插入多个行数据的过程中遇到分区未定义的值时,MyISAM和InnoDB存储引擎的处理完全不同。MyISAM引擎会将满足要求的数据插入,不满足要求的数据不插入。而InnoDB引擎会将整个插入看作一个事务,即一条数据都不会插入。 

6.3 HASH分区

  根据用户定义的表达式返回值来进行分区,返回值不能为负数。数据库会将数据均匀分布到预先定义的各个分区中,保证各分区的数据数量大致都是一样的。例如:

create table t_hash(
    a int,
    b datetime
)engine=innodb
partition by hash (year(b)),
partitions 4;

    如果没有partitions子句,那么分区的数量将默认为1。 

6.4 KEY分区

  key分区和hash分区相似,不同之处在于hash分区使用用户定义的函数进行分区,key分区使用数据库提供的函数进行分区。例如:

create table t_key(
    a int,
    b datetime
) engine = innodb
partition by key(b)
partitions 4;

6.5 COLUMN分区

  range、list、hash、key分区中,分区的条件是数据必须是整型,如果不是整型,那应该需要通过函数将其转换为整型。MySQL5.5开始支持COLUMNS分区,时range和list分区的一种进化,column分区可以直接使用非整型的数据进行分区。range columns分区可以对多个列值进行分区。

create table t_columns_range(
    a int,
    b datetime
)engine=innodb
partition by range columns (b)(
partition by values less than ('2009-01-01')
partition by values less than ('2010-01-01')
);

    对于range columns分区,可以使用多个列进行分区,例如:

create table rcx(
    a int,
    b int,
    c char(3),
    d int
)engine=innodb
partition by range columns(a, d, c)(
partition p0 values less than (5, 10, 'ggg'),
partition p1 values less than (10, 20, 'mmm'),
partition p2 values less than (15, 30, 'sss'),
partition p3 values less than (maxvalue, maxvalue, maxvalue)
);

 6.6 子分区

  子分区是在分区的基础上再进行分区,有时也称为复合分区,MySQL数据库允许在range和list分区上再进行hash或key的子分区。例如:

create tables ts(
    a int, 
    b date
)engine = innodb
partition by rangge(year(b))
subpartition by hash(to_days(b))
subpartitions 2 (
partition p0 values less than (1990),
partition p1 values less than (2000),
partition p2 values less than maxvalue
);

    表ts先根据b列进行range分区,range会产生3个分区,然后每个range分区再进行hash分区,每个range分区产生2个hash分区。因此总共有6个分区。 

6.7 分区中的NULL值

    MySQL数据库允许对NULL值做分区,但是处理方法和其他数据库可能完全不同,MySQL总是视NULL值小于任何一个非NULL值,因此对于不同的分区类型,MySQL数据库对于NULL值的处理也是各不相同。

  • range分区,如果向分区插入了null值,则mysql数据库会将该值放在最左边的分区;
  • list分区,必须显式地之处哪个分区中放入null值,否则会报错;
  • hash和key分区对于null值的处理方式和range分区、list分区不一样,任何分区函数都会将含有null值的记录返回为0.

6.8 分区性能

  对于OLAP的应用,分区的确是可以很好地提高查询性能,因为OLAP应用大多数查询需要频繁的扫描一张很大的表。然而对于OLTP的应用,分区应该非常小心。

  例如,对表profile的主键ID进行hash分区,hash分区的数量为10,表profile有接近1000w的数据:

create table profile(
    id int(11) not null auto_increment,
    nickname varchar(20) not null default '',
    password varchar(32) not null default '',
    sex char(1) not null default '',
    rdate date not null default '0000-00-00',
    primary key ('id'),
    key nickname (nickname)
)engine = innodb
partition by hash(id)
partitions 10;

    如果进行主键的查询,可以发现分区确实是有意义的,因为只会寻找其中某个分区,但是对于表中非主键列的查询,数据库会搜索所有分区,因此查询速度会慢很多。

    因此,对于OLTP应用的表上使用分区应该十分小心,设计时应该确认数据的访问模式,否则OLTP模式下,分区不仅不可能带来性能的提升,反而会执行的更慢。

参考:《Mysql技术内幕-- InnoDB存储引擎》

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值