变更普通表baby_user_change_log为分区表




一、 表列描述

     mysql> desc baby_user_change_log ;

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

     | Field        | Type             | Null | Key | Default | Extra          |

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

     | id           | int(11) unsigned | NO   | PRI | NULL    | auto_increment |

     | account_id   | int(11) unsigned | NO   | MUL | NULL    |                |

     | app_id       | int(11)          | YES  |     | NULL    |                |

     | operate      | varchar(20)      | YES  |     | NULL    |                |

     | old_data     | varchar(2000)    | YES  |     | NULL    |                |

     | new_data     | varchar(2000)    | YES  |     | NULL    |                |

     | change_data  | varchar(2000)    | YES  |     | NULL    |                |

     | operate_time | int(11)          | YES  |     | NULL    |                |

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


二、 表结构特征


      CREATE TABLE `baby_user_change_log` (

      `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',

      `account_id` int(11) unsigned NOT NULL COMMENT 'account_id',

      `app_id` int(11) DEFAULT NULL COMMENT '平台ID',

      `operate` varchar(20) DEFAULT NULL COMMENT '操作类型',

      `old_data` varchar(2000) DEFAULT NULL COMMENT '修改之前的数据',

      `new_data` varchar(2000) DEFAULT NULL COMMENT '修改之后的数据',

      `change_data` varchar(2000) DEFAULT NULL COMMENT '被修改的数据',

      `operate_time` int(11) DEFAULT NULL COMMENT '时间',

      PRIMARY KEY (`id`),

      KEY `idx_account_id` (`account_id`)

      )ENGINE=MyISAM AUTO_INCREMENT=18543058 DEFAULT CHARSET=utf8;


三、适合的分区方案


      1)表总数据记录条数:

      mysql> select count(*) from baby_user_change_log;

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

      | count(*) |

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

      | 18552945 |

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

      

      2)其中app_id 列具有按照RANGE分区的特征

      

      mysql> select distinct(app_id) from baby_user_change_log;

      +--------+

      | app_id |

      +--------+

      |      7 |

      |      5 |

      |      3 |

      |      1 |  

      +--------+  

     

      3)具体的分区表结构SQL

      

       CREATE TABLE `baby_user_change_log_partition` (

       `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',

       `account_id` int(11) unsigned NOT NULL COMMENT 'account_id',

       `app_id` int(11) DEFAULT NULL COMMENT '平台ID',

       `operate` varchar(20) DEFAULT NULL COMMENT '操作类型',

       `old_data` varchar(2000) DEFAULT NULL COMMENT '修改之前的数据',

       `new_data` varchar(2000) DEFAULT NULL COMMENT '修改之后的数据',

       `change_data` varchar(2000) DEFAULT NULL COMMENT '被修改的数据',

       `operate_time` int(11) DEFAULT NULL COMMENT '时间',

       PRIMARY KEY (`id`,`app_id`),

       KEY `idx_account_id` (`account_id`)

       )ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8

       PARTITION BY RANGE (app_id) (

       PARTITION p0 VALUES LESS THAN (1),

       PARTITION p1 VALUES LESS THAN (3),

       PARTITION p2 VALUES LESS THAN (5),

       PARTITION p3 VALUES LESS THAN (7),

       PARTITION p4 VALUES LESS THAN MAXVALUE

       );  

      

      4)插入数据

        

        insert into baby_user_change_log_partition select* from baby_user_change_log;

     

      5)验证结果

      

      mysql> explain partitions select *  from baby_user_change_log_partition where app_id=1;

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

      | id | select_type | table                                   | partitions | type | possible_keys | key        | key_len | ref   | rows  | Extra |

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

      |  1 | SIMPLE      | baby_user_change_log_partition | p1         | ref  | idx_app_id    | idx_app_id | 4       | const | 25739 |       |

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

      1 row in set (0.00 sec)

      

      mysql> explain partitions select *  from baby_user_change_log_partition where app_id=7;

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

      | id | select_type | table                                   | partitions | type | possible_keys | key        | key_len | ref   | rows | Extra |

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

      |  1 | SIMPLE      | baby_user_change_log_partition | p4         | ref  | idx_app_id    | idx_app_id | 4       | const |  276 |       |

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

      1 row in set (0.00 sec)

      

      mysql> explain partitions select *  from baby_user_change_log_partition;

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

      | id | select_type | table                                   | partitions     | type | possible_keys | key  | key_len | ref  | rows  | Extra |

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

      |  1 | SIMPLE      | baby_user_change_log_partition | p0,p1,p2,p3,p4 | ALL  | NULL          | NULL | NULL    | NULL | 56269 |       |

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

      1 row in set (0.00 sec)



四、 分区表的原理及优缺点



     1)分区表是什么?分区表是由多个相关的底层表实现,这些底层表也是由句柄对象表示,所以我们也可以直接访问各个分区,

        存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎),分区表的索引只是在各个

        底层表上各自加上一个相同的索引,从存储引擎的角度来看,底层表和一个普通表没有任何不同,存储引擎也无须知道这是

        一个普通表还是一个分区表的一部分。

     

     2)在分区表上的操作按照下面的操作逻辑进行:

     

        1.select查询:

     

          当查询一个分区表的时候,分区层先打开并锁住所有的底层表,优化器判断是否可以过滤部分分区,

          然后再调用对应的存储引擎接口访问各个分区的数据

     

        2.insert操作:

     

          当写入一条记录时,分区层打开并锁住所有的底层表,然后确定哪个分区接受这条记录,再将记录写入对应的底层表

     

        3.delete操作:

     

          当删除一条记录时,分区层先打开并锁住所有的底层表,然后确定数据对应的分区,最后对相应底层表进行删除操作

     

        4.update操作:

     

          当更新一条数据时,分区层先打开并锁住所有的底层表,mysql先确定需要更新的记录在哪个分区,然后取出数据并更新,

          再判断更新后的数据应该放在哪个分区,然后对底层表进行写入操作,并对原数据所在的底层表进行删除操作

     

     3)虽然每个操作都会打开并锁住所有的底层表,但这并不是说分区表在处理过程中是锁住全表的,如果存储引擎能够自己实现行级锁,

         如:innodb,则会在分区层释放对应的表锁,这个加锁和解锁过程与普通Innodb上的查询类似。

     

     4)分区表适用的场景

     

        1.表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他都是历史数据

     

        2.分区表的数据更容易维护,如:想批量删除大量数据可以使用清除整个分区的方式。另外,

          还可以对一个独立分区进行优化、检查、修复等操作

     

        3.分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备

     

        4.可以使用分区表来避免某些特殊的瓶颈,如:innodb的单个索引的互斥访问,ext3文件系统的inode锁竞争等

     

        5.如果需要,还可以备份和恢复独立的分区,这在非常大的数据集的场景下效果非常好

     

        6.优化查询,在where字句中包含分区列时,可以只使用必要的分区来提高查询效率,

          同时在涉及sum()和count()这类聚合函数的查询时,可以在每个分区上面并行处理,

          最终只需要汇总所有分区得到的结果。

          

     5)分区表的限制

        

     

        1.一个表最多只能有1024个分区,包含子分区(mysql5.6之后支持8192个分区)

     

        2.在mysql5.1中分区表达式必须是整数,或者是返回整数的表达式,

          在5.5之后某些场景可以直接使用字符串列和日期类型列来进行分区

          使用varchar字符串类型列时,一般还是字符串的日期作为分区。

     

        3.如果分区字段中有主键或者唯一索引列,那么所有主键列和唯一索引列都必须包含进来,

          如果表中有主键或唯一索引,那么分区键必须是主键或唯一索引

     

        4.分区表中无法使用外键约束

     

        5.mysql数据库支持的分区类型为水平分区,并不支持垂直分区,

          因此mysql数据库的分区中索引是局部分区索引,一个分区中既存放了数据又存放了索引,

          而全局分区是指的数据库放在各个分区中,但是所有的数据的索引放在另外一个对象中

     

        6.目前mysql不支持空间类型和临时表类型进行分区。不支持全文索引

     


五、分区表的分区类型

     

    1)分区表根据数据类型的特征适用不同的分区类型主要的类型有:

    

       1.RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。


       2.LIST分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。


       3.HASH分区:基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。

         这个函数可以包含MySQL 中有效的、产生非负整数值的任何表达式。


       4.KEY分区:类似于按HASH分区,区别在于KEY分区只支持计算一列或多列,且MySQL服务器提供其自身的哈希函数。

         必须有一列或多列包含整数值。




     分区表官方文档的解释与说明:

    

     http://dev.mysql.com/doc/refman/5.5/en/partitioning.html