1.前言

  上一章记录了MySQL中的一些文件组成,以及相关作用和参数配置,本章开始记录深层次的存储结构,以便更好理解MySQL的设计。

2.索引组织表

  InnoDB中,表都是根据主键顺序组织存放的,这种方式称为索引组织表。每个表都有一个主键,没有主键会按照一定规则选择或创建主键:

    判断表中是否有非空唯一索引,有则为主键,多个按建表时定义顺序的第一个作为主键,这个意思并不是SQL语句的顺序。

    没有,自动创建一个6字节的指针,_rowid,通过这个字段可以查看主键(对复合主键无能为力)

3.InnoDB逻辑存储结构

  前几章说了InnoDB的一些概念,比如共享表空间ibdata1,单表表空间,页,区等,这里对其逻辑结构进行详细记录说明。

  InnoDB的数据被逻辑地存放在一个空间中,称为表空间。表空间又由段(segment)、区(extent)、页(page)组成,页有时也被称为块(block)。

3.1 表空间

  用户启动参数innodb_file_per_table,每张表数据单独放到一个表空间。只存放数据,索引和缓冲bitmap页。其他数据如回滚信息,插入缓冲索引页,系统事务信息,二次写缓冲都还是存放在共享表空间中。打开一个手动提交的事务,修改表数据,可以观察到共享表空间大小增大,这就说明undo页存放在共享表空间中,执行回滚并不会变小,只是标记这些undo页可用而已。

3.2 段

  表是由段组成的,常见的段有数据段、索引段、回滚段等。InnoDB是索引组织结构,所以数据就是索引,数据段就是B+树的叶子节点,索引段就是B+树的非叶子节点。回滚段较特殊。

3.3 区

  区是由连续的页组成的,大小固定1MB,为了保证页的连续性,InnoDB一次会申请4~5个区。默认情况,页大小16KB,1个区里面有64个连续的页。

  1.0版本开始有压缩页,每个页大小可以通过参数KEY_BLOCK_SIZE设置为2K、4K、8K,对应区的页数为512,256,128。

  1.2版本增加参数innodb_page_size,将默认的页大小设置为4K、8K,页中的数据库不是压缩。区的大小始终是1MB。

  在为每张表创建表空间的时候,会发现创建的表默认大小是96KB,区不是固定1MB吗?这是因为在每个段开始的时候,会使用32个页大小的碎片页,使用完了之后才会申请64个页,减少磁盘开销。

3.4 页

  InnoDB页是磁盘管理的最小单位,默认大小16kb。1.2版本开始,可以通过参数innodb_page_size将页的大小设置成4K、8K、16K。设置完成,所有页的大小都是innodb_page_size。不能对其再次修改,除非通过mysqldump导入和导出操作产生新的库。

  常见的页类型有:

    数据页、undo页、系统页、事务数据页、插入缓冲bitmap、插入空闲free列表页、未压缩的二进制大对象页、压缩的二进制大对象页。

3.5 行

  InnoDB存储引擎是面向列的,也就是说数据是按行进行存放的。每页最多放16KB / 2~200行的数据,即7992行。

4. InnoDB行记录格式

  页中保存一行行的数据,以链表的形式存储。在1.0版本之前,提供了Compact和Redundant两种格式来存放记录,后者是为了兼容之前版本保留的。通过SHOW TABLE STATUS LIKE ”table_name"查看当前表使用的格式。row_format属性表示当前使用的行记录结构。创建表的时候可以指定:create table name engine=xxx row_format=xxx

4.1 Compact格式

  MySQL5.0版本引入,目标是高效地存储数据。简单来说,一个页存放的数据越多,性能越高。具体格式如下:

  变长字段长度:列的长度小于255,使用1字节存放,大于255,使用2字节。因为varchar最大65535。是按列顺序的逆序存放其长度的。

  NULL标志位:表明列中是否有NULL值。有为1。1个字节

  记录头信息:5个字节,40位

    1~2:未知

    3:该行是否已被删除

    4:为1,如果该记录是预先被定义为最小的记录

    5~8:该记录拥有的记录数

    9~21:索引堆中该条记录的排序记录

    22~24:记录类型:000普通,001B+树节点指针,010 Infimum, 011 Supermum, 1xx保留

    25~40:页中下一条记录的相对位置。(这个就是链表的原因)

  最后就是实际列的数据了,NULL不占空间,只有NULL标志位。还有两个隐藏列:事务ID列和回滚指针列,分别是6字节和7字节。没有主键,会产生rowid,6个字节。在记录头后面,列数据前面。

  char类型空间未用完,会填充0x20。

4.2 Redundant行记录格式

  偏移列表,同样是按字段列的逆序放置。长度小于255,用1字节表示,大于255用2字节表示。与长度列表不同的是,这里定位的是偏移量,后者的偏移量等于前者的+前者保存的长度

  头信息:6个字节,48位

    1~2:未知

    3:该行是否删除

    4:为1,如果该记录是预先被定义为最小的记录

    5~8:该记录拥有的记录数

    9~21:索引堆中该条记录的索引号

    22~31:记录中的列数量

    32:偏移列表为1字节还是2字节

    33~48:下一条记录的位置

  列数量使用了10个字节记录,所以mysql支持的最大列数是2^10-1=1023列。

  这种格式varchar的NULL是不占空间的,但是char需要占用空间。

4.3 行溢出数据

  InnoDB可以将一条记录中的某些数据存储在数据页之外,比如BLOB、LOG这类大对象列。BLOB可以不将数据放入溢出页面,但是varchar列数据却也可能被放在溢出数据。

  varchar虽然使用2个字节记录长度,理论上可以存放65535字节,但是实际创建的时候不支持这么大的,因为还有其他开销,最大长度应该是65532.(2个字节记录长度,1个字节用于NULL)

  另外要注意的是65532针对的字符类型是Latin1的,如果是GBK或者UTF8又会失败。

  VARCHAR(N)指的是字符的长度,而最大支持是指字节,所以GBK的话大概是32766,UTF-8是21845超过这个值且数据库SQL_MODE没有设置成严格,会警告,并自动转为text类型。

  此外,VARCHAR指的是一条记录中所有VARCHAR字段的总长度限制。比如一张表里有3个varchar字段,每个长度22000,总长度就660000了,这样创建是会失败的。

  InnoDB中一页是16KB,16384字节,怎么放下varchar呢。一般情况数据是存放在页类型为B-tree node中,但是发生行溢出时,数据放在页类型为Uncompress BLOB页中。前面一部分空间存放数据,后面通过一个偏移量指向溢出页。问题来了,多长的varchar会保存在页中,从多长开始保存在BLOB页中:

  首先要清楚页的存储结构是B+树,如果只能存放一条记录,那么就没有意义了,所以一条记录超过页大小的时候,就会被放入溢出页中。如果能放入两条记录的话,大小阈值是多少才会被放入BLOB中呢,大概是8098。两条这么长的varchar记录依旧会在一页之中。另外,Text和BloB的数据类型也不是总是放在Uncompressed BLOB Page中的,和之前一样,要保证一个页存放两条记录。

4.4 Compressed和Dynamic行记录格式

  1.0版本开始引入新的文件格式,以前的Compact和Redundant格式称为Antelope文件格式,新的是Barracuda:Compressed和Dynamic两种格式。

  新的格式对于存放BLOB中的数据采取了完全的行溢出方式,只存放20个字节的指针,数据都放在Off Page中,之前的格式会存放768个前缀字节。Compressed行记录格式的另一个功能就是,存储在其中的行数据会以zlib的算法进行压缩,因此对于BLOB、TEXT、VARCHAR这类大长度类型的数据能够进行有效的存储。

4.5 CHAR的行结构存储

  从4.1开始CHR(N)中的N指的是字符的长度,不是字节的长度了。因此CHAR类型的内部存储可能不是定长的数据。所以在内部将CHAR也视为变长字符类型,这就意味着变长长度列表中会记录CHAR数据类型的长度,对于未占满长度的字符还是填充0x20.

5.InnoDB数据页结构

  数据页由7个部分组成:File Header文件头、Page Header页头、Infimum和Supermum Records、User Record行记录、Free Space空闲空间、Page Directory页目录、File Trailer文件结尾信息。其中头尾大小是固定的,分别是38、56、8字节,这些空间用来记录一些该页的信息,如checksum,数据页在B+树索引的层数等。其它的是实际的行记录存储空间,是动态的。

5.1 File Header

  由8个部分构成,共38个字节:

    FIL_PAGE_SPACE_OR_CHECKSUM  4字节  mysql4.0.14之前,该值为0,后面代表checksum的值

    FIL_PAGE_OFFSET           4字节  表空间页的偏移量。如独立表空间大小为1GB,该页16KB,一共65536个页,这个就表示该页在所有页中的位置。若表空间ID是10,那么searchKey(10,1)就是查找表中的第二个页。

    FIL_PAGE_PREV           4字节  当前页的上一个页,B+树决定了叶子节点必须是双向列表

    FIL_PAGE_NEXT           4字节  当前页的下一个页

    FIL_PAGE_LSN            8字节  该页最后被修改的日志序列位置LSN

    FIL_PAGE_TYPE           2字节  InnoDB存储引擎页类型,0x45BF代表存放的是页数据

        0x0002  undo log 页

        0x0003  索引节点

        0x0004  insert buffer空闲列表

        0x0000  新分配的页

        0x0005  insert buffer bitmap

        0x0006  系统页

        0x0007  事务系统数据

        0x0008  File Space Header

        0x0009  扩展描述页

        0x000A  BLOB页

    FIL_PAGE_FILE_FLUSH_LSN     8字节   该值仅在系统表空间的一个页中定义,代表文件至少被更新到了该LSN值。独立表都是0

    FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID  4字节  从MySQL4.1开始该值表示页属于哪个表空间。

5.2 Page Header

  该部分用来记录数据页的状态信息,由14个部分组成,共占用56字节。

    PAGE_N_DIR_SLOTS    2    在Page Directory(页目录)中Slot(槽)数,‘4.4.5 Page Directory’小节中会介绍

    PAGE_HEAP_TOP       2    堆中第一个记录的指针,记录在页中是根据堆形式存放的

    PAGE_N_HEAP         2    堆中的记录数。一共占用2字节,但是第15位表示行记录格式

    PAGE_FREE         2    执向可重用空间的首指针

    PAGE_GARBAGE      2    已删除记录的字节数,即行记录结构中delete flag为1的记录大小的总数

    PAGE_LAST_INSERT    2     最后插入记录的位置

    PAGE_DIRECTION      2     最后插入的放向,可能是0x01 left、0x02 right、0x03 same rec、0x04 same page、0x05 no direction

    PAGE_N_DIRECTION    2     一个方向连续插入记录的数量

    PAGE_N_RECS        2     该页中记录的数量

    PAGE_MAX_TRX_ID     8      修改当前页的最大事务ID,注意该值仅在Secondary Index中定义

    PAGE_LEVEL         2      当前页在索引树中的位置,0x00代表叶节点,即叶节点总是在第0层

    PAGE_INDEX_ID      8      索引ID,表示当前页属于哪个索引

    PAGE_BTR_SEG_LEAF     10    B+树数据页非叶节点所在段的segment header。注意该值仅在B+树的ROOT页定义

    PAGE_BTR_SEG_TOP    10    B+树数据页所在段的segment header.注意该值仅在B+树的Root页定义

5.3 Infimum和Supermum Record

  每个数据页由两个虚拟的行记录,用来限定记录的边界。Infimum记录是比该页中任何主键都要小的值,Supermum是比任何可能大的值都大的值。在页创建的时候被建立,并且不会被删除。

5.4 User Record和Free Space

  User Record就是实际存储记录的内容。

  Free Space就是空闲空间,链表结构。

5.5 Page Directory

  页目录保存了记录的相对位置,这里放的是页的相对位置,不是偏移量。这些记录指针有时被称为槽或者目录槽。不是每个记录都有槽的,这是一个稀疏目录,一个槽中可能包含多个记录。在槽中按照索引键值顺序存放,这样可以使用二叉查找迅速找到记录的指针,但是由于是稀疏目录,所以只能查到一个初略的结果,还需要通过reocorder header中的next_record来继续查找。

  B+树不能定位到具体记录,只能定位到记录所保存的页,然后将页加载到内存,通过Page Directory进行二叉查找定位到具体记录。

5.6 File Tailer

  这个用于校验数据是否完整写入磁盘,占用8个字节,前4个表示checksum,后四个与File Header的FIL_PAGE_LSN相同。

  该校验会对系统有些开销,innodb_checksums可以关闭这个校验。

  MySQL5.6.6版本开始新增了参数innodb_checksum_algorithm,用来控制检测checksum的算法,默认crc32。可设置的有:innodb、crc32、none、strict_innodb、strict_crc32、strict_none。

  innodb算法是用于兼容之前版本的checksum检测方式,crc32是5.6.6版本引进的新的checksum算法,性能比innodb高。用strict算法保存,低版本的MySQL库无法读取这些页。none不检测。启动strict_crc32是最快的,他不会对innodb和crc32算法进行两次检测,但是低版本无法使用。

6. Named File Formats机制

  随着存储引擎的发展,新的页数据结构有时用于支持新的功能特性。比如前面提到的表压缩功能等。这些数据结构和之前的版本并不兼容,所以在1.0版本开始,InnoDB存储通过Named File Formats机制来解决不同版本下页结构兼容性问题。

  1.0版本之前的称为Antelope,之后的为Barracuda,新版的文件格式总是包含旧版的内容。SHOW VARIABLES LIKE ’innodb_file_format'

7 约束

7.1 数据完整性约束

  关系型数据库本身保证存储数据的完整性,提供了约束机制,通常有3种形式:

    1.实体完整性:保证表中有一个主键,可以定义Primary Key,Unique Key。

    2.域完整性:保证数据每列满足特定条件。以下途径可以保证:选择合适的数据类型保证数据值满足条件,外键约束,编写触发器,用DEFAULT。

    3.参照完整性:保证两张表之间的关系,外键。

  InnoDB提供了以下几种约束:

    Primary Key

    Unique Key

    Foreign Key

    Default

    NOT NULL

7.2 约束的创建和查找

  创建方式:

    表建立时定义

    ALTER TABLE命令创建约束

  对于唯一索引约束Unique Key,用户还可以通过命令CREATE UNIQUE INDEX来创建。

  对主键约束,名为PRIMARY,对于Unique Key约束,约束名和列名一样。Foreign Key约束似乎会有一个比较神秘的默认名称。

7.3 约束和索引的区别

  创建约束的方法不就是创建索引吗,有什么区别?约束是一个逻辑的概念,用来保证数据的完整性。索引是一个数据结构,有逻辑的概念,也代表着物理存储方式。

7.4 对错误数据的约束

  在某些默认设置下,MySQL数据库允许非法的或不正确的插入数据或更新,或者在内部转换成一个合法的值,如向NOT NULL字段插入一个NULL值,数据库会将其改为0再进行插入。这个是通过设置sql_mode完成的。SET sql_mode = "STRICT_TRANS_TABLES",这个类型对输入进行了约束。

7.5 ENUM和SET约束

  MySQL不支持传统的CHECK约束,但是可以通过ENUM和SET类型解决部分需求。比如表上有一个性别类型,范围只有male或者female,这个时候可以使用ENUM约束。创建表的时候sex字段为ENUM('male','female')。只支持离散数据类型,对连续的无能为力。

7.6 触发器约束

  MySQL5.1开始触发器相对稳定。CREATE TRIGGER,只有super权限的用户才能执行。最多可以为一个表创建6个触发器,即分别为INSERT、UPDATE、DELETE的before和after各定义一个。当前MySQL只支持FOR EACH ROW的触发方式,即按每行记录进行触发。

  CREATE

  [DEFOMER = {user | CURRENT_USER}]

  TRIGGER trigger_name BEFORE | AFTER   INSERT|UPDATE|DELETE

  ON table_name FOR EACH ROW trigger_stmt。

  通过触发器可以实现一些不支持的特性,比如CHECK约束,物化视图,高级复制,审计等特性。比如买东西,每次都是减的,但是如果用户输入了一个负数,就变成加了。这个时候就可以通过触发器来完成这个判断了。

7.7 外键约束

  外键用来保证参照完整性,MySQL数据库的MyISAM引擎本身不支持外键,对外键的定义只是一个注释作用。

  [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

    CASCADE表示父表发生DELETE或UPDATE操作时,对应子表数据也进行DELETE或UPDATE操作。

    SET NULL 表示父表发生DELETE或UPDATE操作时,子表设置NULL

    NO ACTION表示子表有相关联记录,抛出异常,不允许操作

    RESTRICT表示父类发生DELETE或UPDATE操作时,抛出错误,不允许这类操作。

  Oracle数据库有一种延时检查的外键约束,检查在SQL执行之后进行,但MySQL都是即时检查,所以NO ACTION和RESTRICT没区别。默认使用RESTRICT。

  MySQL会自动为外键创建索引,避免死锁问题。

8 视图

  MySQL中视图是一个命名的虚表,它由一个SQL查询来定义,可以当做表使用。与持久表不同,视图没有实际的物理存储。

8.1 视图的作用

  视图的主要作用之一是用做一个抽象装置,程序本身不需要关心基表的结构,只需要按照视图定义来取数据或更新数据,一定程度上起到了安全层的作用。5.0版本开始支持视图:

    CREATE [OR REPLACE]

    [ALGORITHM = { UNDEFINED | MERGE | TEMPTABLE}]

    [DEFINER =  {user | CURRENT_USER }]

    [SQL SECURITY { DEFINER | INVOKER }]

    VIEW view_name [(column_list)]

    AS select_statement

    [WITH [CASCADED | LOCAL] CHECK OPTION]

  虽然视图是虚拟表,但是可以对其进行更新,本质上就是更新基本表。可能更新失败,带上WITH CHECK OPTION会失败的时候抛出异常。

8.2 物化视图

  Oracle支持物化视图,即该视图不是基于基表的虚表,而是根据基表实际存在的实表,存储在非易失的存储设备上。

  物化视图用于预先计算并保存多表的链接或者聚集等耗时较多的SQL操作结果。这样,执行复杂查询时,就可以避免进行这些耗时的操作。Oracle中创建方法有两种:

    BUILD IMMEDIATE:默认方式,在创建的时候就生成数据

    BUILD DEFERRED:根据需要生成数据

  查询重写就是会自动判断是否能通过查询物化视图得到最终结果,如果可以就避免了复杂的SQL操作。

  物化视图的刷新是指基表发生了DML操作后,物化视图何时采用哪种方式和基表进行同步:

    ON DEMAND:在用户需要的时候进行刷新

    ON COMMIT:对基表的操作提交时同步进行

  刷新的方式有4种:

    FAST:增量刷新,只刷新自上次刷新后的修改

    COMPLETE:全量刷新

    FORCE:刷新的时候会去判断,能快速刷新使用FAST,不能使用COMPLETE.

    NEVER:不刷新

  MySQL不支持物化视图,可以自己实现,比如定时将一个表导入另一个表。这个就是ON DEMAND类型。这自然是COMPLETE刷新方式,要实现FAST就比较复杂了,统计上次刷新的位置。实现ON COMMIT就复杂了,可以通过触发器。

  查询重写功能MySQL就无能为力了,需要在应用端进行控制。

9 分区表

9.1 分区概述

  分区功能不是在存储引擎层完成的,所以InnoDB、MyISAM、NDB等都支持,但是也有不支持的,比如:CSV、FEDORATED、MERGE等。

  MySQL5.1版本添加了对分区的支持。这个过程是一个将表或索引分解为多个更小、更可管理的部分。从逻辑上讲,只有一个表或者一个索引,但是在物理上这个表或者索引可能由数十个物理区组成,这样就可以对各个部分处理的能力了。

  MySQL支持的分区类型是水平分区,不支持垂直分区。分区是局部分区索引,一个分区中既存放了数据又存放了索引,全局分区指的是数据存放在各个分区,但是索引存放在一个对象中。目前MySQL不支持全局分区。通过SHOW VARIABLES LIKE '%partition%'查看是否启用了分区。也可以使用SHOW PLUGINS查看。

  分区不一定会让数据库更快,可能会提高某些SQL的性能,但是分区主要是用于数据库的高可用性管理。在OLTP应用中,对分区的使用应该非常小心。

  MySQL数据库支持的分区类型有:

    RANGE分区:行数据基于属于一个给定连续区间的列值被放入分区。MySQL5.5开始支持RANGE COLUMNS的分区

    LIST分区:和RANGE分区类型,只是LIST分区面向的是离散的值。MySQL5.5开始支持LIST COLUMNS分区

    HASH分区:根据用户自定义的表达式的返回值来进行分区,返回值不能为负数。

    KEY分区:根据MySQL数据库提供的哈希函数进行分区。

  不论创建什么类型的分区,如果表中存在主键或者唯一索引时,分区列必须是唯一索引的一个组成部分。比如唯一索引是a,b,创建PARTITION BY hash(c)就不行,c不是a,b的一个组成部分。如果表没有主键,唯一索引,可以指定任何一个列为分区列。

  分区的目的是将数据分割,查询的范围就小了,这样速度就快了,所以要考虑表执行的SQL是否适合分区,万一分区却扫描了全表,那么就得不偿失了。

9.2 分区类型

9.2.1 RANGE分区

  Partition By Range(id) (

    Partition p0 values less than (10),

    Partition p1 values less than (20)

  );

  id小于10的插入p0,大于等于10,小于等于20的插入p1。

  启用分区后,物理磁盘上就不是一个ibd文件了,会有各个分区的ibd文件。

  另外,由于没有定义大于等于20的情况,插入这个会抛出异常。对于这种情况可以写成

    ALTER TABLE t ADD PARTITION( partition p2 values less than maxvalue);

  RANGE分区主要用于日期列的分区,例如对于销售类的表,可以根据年来分区存放销售记录。Partition by range (year(date)) (partition p2008 values less than(2009));

  这样的好处在于我们删除08年的数据只需要:alter table sales drop partition p2008;

  另一方面,查询08年的数据也只会查这个分区。EXPLAIN  PARTITIONS,但是如果查询08和09年的就会跨分区了,这个是不好的操作。

  如果按月进行分区,实际上查询并不会只查那个月的,优化器不一定会根据分区选择。因为对RANGE分区的查询,优化器只对YEAR()、TO_DAYS()、TO_SECONDS()、UNIX_TIMESTAMP()这类函数进行优化选择,所以如果按月查询,要写成:

    Partition By range(To_DAYS(date)) (

      Partition p201001 values less than (to_days('2010-02-01'))

    );

9.2.2 LIST 分区

  LIST分区和RANGE很相似,但是值是离散的,而不是连续的。range中使用values less than,list中使用values in,毕竟值是离散的。如果插入的值不在定义中,也会抛出异常。

  此外对于多行插入中存在未定义的值,MyISAM会将之前的数据都插入,遇到未定义的之后的不插入。InnoDB都不插入。

  partition by list(b) (

    partition p0 values in (1,2,3,4,5)

  );

9.2.3 hash分区

  hash分区的目的是将数据均匀的分布到预先定义的各个分区中,保证各分区的数据量大致都一样。hash分区中,数据库自动完成这个操作。

    Partition by hash(expr) expr是一个返回整型的表达式,后面还要跟上一个partitions num,表示分多少个区。

  MySQL还支持一种LENEAR HASH。优点在于增加、删除、合并、拆分分区更加快捷。缺点在于各分区的数据分布可能不大均衡。

9.2.4 KEY分区

  KEY与HASH相似,不同在于HASH分区使用用户定义的函数进行分区,KEY分区使用MySQL数据库提供的函数进行分区。对于NDB Cluster引擎,使用MD5函数分区。对于其他引擎,使用内部的hash函数。

9.2.5 COLUMNS分区

  前面介绍的分区条件都要是整型,不是整型要通过函数转变成整型,比如YEAR等。COLUMNS分区可以直接使用非整型的数据进行分区,分区根据类型直接比较而得。

  COLUMNS分区支持以下的数据类型:

    所有的整型类型:FLOAT和DECIMAL不支持

    日期类型:DATE和DATETIME,其余不支持

    字符串类型:如CHAR、VARCHAR、BINARY、VARBINARY。BLOB和TEXT不支持。

9.3 子分区

  子分区是在分区的基础上再进行分区,也称复合分区。SUBPARTITION。

  子分区要注意:

    1.每个子分区的数量必须相同

    2.要在一个分区表的任何分区上使用SUBPARTITION来明确定义任何子分区,就必须定义所有的子分区。

      每个SUBPARTITION子句必须包括子分区的一个名字。

      子分区不能重名。

9.4 分区中的NULL值

  mysql允许使用NULL值做分区,把NULL看做比所有非NULL都小的值。这个操作和order by操作是一样的。所以对不同的分区类型,对NULL的操作也不同。

  range分区中,会放在最左边的分区,

  list分区,要显示指出放在哪个分区,PARTITION p0 VALUES in (NULL)

  hash和key分区和前两个不同,任何函数都将含有NULL的记录返回为0.

9.5 分区和性能

  使用分区不一定会带来查询速度的提升,要明确其使用环境。

  数据库应用分为两类:OLTP(在线事务处理),比如Blog、电子商务、网络游戏。

            OLAP(在线分析处理),比如数据仓库、数据集市。

  对后者会有性能的提高,因为大部分查询要频繁的扫描一张很大的表。

  对于OLTP的应用,分区就要非常小心了。通常只需要返回几条记录,对B+树而言,大概需要2~3次磁盘IO,所以本身可以很好完成操作,不需要分区支持,设计不好反而会带来严重的性能问题。

9.6 在表和分区间交换数据

  MySQL5.6开始支持ALTER TABLE ... EXCHANGE PARTITION语法,支持分区的数据与非分区的表中数据进行交换。如果非分区表数据为空,等于将分区的数据移动到非分区。若分区表中数据为空,等于将外部表数据导入分区中。

  满足以下条件才行:

    表和分区表有相同的表结构,但表中不能有分区

    非分区表中的数据必须在交换的分区定义内

    被交换的表不能含有外键,或者其他的表含有对该表的外键引用

    用户处理ALTER INSERT 和CREATE权限外,还需要DROP权限

  还要注意:

    使用过程中,触发器不会被触发

    AUTO_INCREMENT列会被重置。

MySQL笔记(4)---表的更多相关文章

  1. mysql系列十一、mysql优化笔记:表设计、sql优化、配置优化

    可以从这些方面进行优化: 数据库(表)设计合理 SQL语句优化 数据库配置优化 系统层.硬件层优化 数据库设计 关系数据库三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非 ...

  2. MYSQL进阶学习笔记八:MySQL MyISAM的表锁!(视频序号:进阶_18-20)

    知识点九:MySQL MyISAM表锁(共享读锁)(18) 为什么会有锁: 打个比方,我们到淘宝买一件商品,商品只有一件库存,这时候如果还有另外一个人也在买,那么如何解决是你买到还是另一个人买到的问题 ...

  3. MySQL笔记汇总

    [目录] MySQL笔记汇总 一.mysql简介 数据简介 结构化查询语言 二.mysql命令行操作 三.数据库(表)更改 表相关 字段相关 索引相关 表引擎操作 四.数据库类型 数字型 字符串型 日 ...

  4. 如何对MySQL 对于大表(千万级)进行优化

    如何对Mysql中的大型表进行优化 @(mysql 笔记) 收集信息 1.数据的容量:1-3年内会大概多少条数据,每条数据大概多少字节: 2.数据项:是否有大字段,那些字段的值是否经常被更新: 3.数 ...

  5. 涂抹mysql笔记-数据库中的权限体系

    涂抹mysql笔记-数据库中的权限体系<>能不能连接,主机名是否匹配.登陆使用的用户名和密码是否正确.mysql验证用户需要检查3项值:用户名.密码和主机来源(user.password. ...

  6. MySQL笔记(六)游标练习

    23.3.1 Trigger Syntax and Examples 意义不明的几道练习,留着备用. 感觉不好写,而且难以调试..不知道以后会不会有实际的应用场景. 环境:MySQL 笔记(三)由 t ...

  7. mysql 笔记(一)

    mysql 笔记 预留 mysql> use mysql; mysql> grant all privileges  on *.* to root@'%' identified by &q ...

  8. 【MySQL笔记】SQL语言四大类语言

     SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL.   1. 数据查询语言DQL 数据查询语言DQL基本结构是由SELECT子句,FROM子句, ...

  9. Mysql 笔记二

    Mysql 笔记二 Mysql 笔记二 Table of Contents 1. 前言 2. Master Thread 工作方式 2.1. 主循环(loop) 2.2. 后台循(backgroup ...

随机推荐

  1. pat树之专题(30分)

    (好好复习是王道) 1115. Counting Nodes in a BST (30) 分析:简单题——将bst树构造出来,然后给每个节点打上高度.最后求出树的高度.然后count树高的节点数加上树 ...

  2. TensorFlow 实现 RNN 入门教程

    转子:https://www.leiphone.com/news/201705/zW49Eo8YfYu9K03J.html 最近在看RNN模型,为简单起见,本篇就以简单的二进制序列作为训练数据,而不实 ...

  3. FPGA速度等级

    转自http://wenku.baidu.com/view/ea793deef8c75fbfc77db263.html?from=rec 最初接触speed grade这个概念时,很是为Altera的 ...

  4. How to temporally disable IDE tools (load manually)

    It is possible to prevent the IDE Tools from being loaded automatically when starting Visual Studio. ...

  5. (转)ASP.NET(C#)FileUpload实现上传限定类型和大小的文件到服务器

    上传文件有两个主要的目的地,一个是服务器,另一个是数据库,ASP.NET内置了FileUpload这个上传控件,文本框显示用户选择的文件的全名. 其属性主要包括: ContenLength:上传文件大 ...

  6. Oracle中B-TREE索引的深入理解(转载)

    索引概述 索引与表一样,也属于段(segment)的一种.里面存放了用户的数据,跟表一样需要占用磁盘空间.只不过,在索引里的数据存放形式与表里的数据存放形式非常的不一样.在理解索引时,可以想象一本书, ...

  7. SSH 等效性问题 总提示输入密码问题

    家目录权限问题 .chmod 700 /home/.. 得到的教训就是没事儿不要乱修改家目录权限,一时方便,可能在别的地方载跟头 ~~ 浪费好许时间 哎

  8. IGServer

    默认运行的服务器程序 (这种没有界面的中间服务件程序但在进程中可以查看到) C/C++ 服务器编程(VS.Linux.测试/维护)C/C++网络编程

  9. Python自动化开发 - 常用模块(一)

    本节内容 1.模块介绍 2.time&datetime模块 3.random模块 4.os模块 5.sys模块 6.json&pickle模块 7.logging模块 一.模块介绍 模 ...

  10. 安卓读写INI文件 安卓读写INI文件

    安卓读写INI文件   安卓读写INI文件 uses System.IoUtils procedure TForm1.Button1Click(Sender: TObject);varIniFile: ...