zoukankan      html  css  js  c++  java
  • MySQL 分区表

    分区表

    分区表是一个独立的罗杰表 但是底层有多个物理子表组成  实现分区的代码实际上是对一组底层表的句柄对象的封装  对分区表的请求 都会通过句柄对象转化成对存引擎的接口调用  所以分区对于SQL层来说是一个完全封装底层实现的黑盒子 对应用是透明的 但是从底层的文件系统来看就很容易发现 每一个分区表都有使用 # 分隔命名的表文件

    在下面的场景中 分区可以起到非常大的作用

    • 表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据。
    • 分区表的数据更容易维护。例如,想批量刪除大量数据可以使用清除整个分区的方式。另外,还可以对一个独立分区进行优化、检查、修复等操作。
    • 分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。
    • 可以使用分区表来避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问、ext3文件系统的inode锁竞争等。
    • 如果需要,还可以备份和恢复独立的分区,这在非常大的数据集的场景下效果非常好。

    分区表本身也有一些限制 下面是其中比较重要的几点

    • 一个表最多只能有1024个分区
    • 在 MySQL 5.1 中 分区表达式必须是整数 或者是返回整数的表达式  在 MySQL 5.5 中 某些场景中可以直接使用列来进行分区
    • 如果分区字段中有主键或者唯一索引的列 那么所有主键列和唯一索引列都必须包含进来
    • 分区表中无法使用外键约束

    分区表的原理

      分区表由多个相关的底层表实现 这些底层表也是由句柄对象表示 所以我们也可以直接访问各个分区 存储引擎管理分区的各个底层表和管理普通表一样 (所有的底层表都必须使用相同的存储引擎) 分区表的索引只是在各个底层表上各自加上一个完全相同的索引  从存储引擎的角度来看 底层表和一个普通表没任何不同 存储引擎也无须知道这事一个普通表还是一个分区表的一部分

    分区表的类型

      例如 下表就是可以将每一年的订单存放在不同的分区里

    CREATE TABLE `st_simple_expressrecord` (
    	`id` INT (11) NOT NULL AUTO_INCREMENT COMMENT 'id',
    	`order_sn` VARCHAR (225) NOT NULL DEFAULT '' COMMENT '单号',
    	`id_user` INT (11) NOT NULL COMMENT '操作人',
    	`callee` VARCHAR (255) NOT NULL DEFAULT '',
    	`state` INT (11) NOT NULL COMMENT '状态101到件 102上架 103分派 104 入柜 305签收 302退回299问题件 202修改 304补签 1点货 203催件 遗留件 306 出柜',
    	`order_date` datetime NOT NULL COMMENT '操作时间',
    	`operator` VARCHAR (255) NOT NULL DEFAULT '',
    	`is_read` INT (11) NOT NULL DEFAULT '0' COMMENT '可见状态 0可见 1不可见',
    	`access` INT (1) NOT NULL DEFAULT '0' COMMENT '0未接 1第一次接入失败 2第二次接入失败 3第三次接入失败  4成功 5不需要接入0未接 1第一次接入失败 2第二次接入失败 3第三次接入失败  4成功 5不需要接入',
    	`express_type` TINYINT (1) NOT NULL DEFAULT '0' COMMENT '0:普通件 1:到付件 2:代收货款件',
    	`epreason` VARCHAR (255) NOT NULL DEFAULT '对接中',
    	`id_brand` INT (3) NOT NULL DEFAULT '0',
    	`id_binding` INT (11) NOT NULL DEFAULT '-1',
    	`code` VARCHAR (255) NOT NULL DEFAULT '',
    	`reason` VARCHAR (255) NOT NULL DEFAULT '',
    	`account` DOUBLE (11, 2) NOT NULL DEFAULT '0.00',
    	`id_partner` INT (11) NOT NULL DEFAULT '-1',
    	`data_source` TINYINT (1) NOT NULL DEFAULT '0' COMMENT '数据来源 1上海 2山西 3其他',
    	PRIMARY KEY (`id`, `order_date`),
    	KEY `aaa` (`order_date`) USING BTREE
    ) ENGINE = INNODB DEFAULT CHARSET = utf8 PARTITION BY RANGE (YEAR(order_date))(
    	PARTITION p0
    	VALUES
    		LESS THAN (2016) ENGINE = INNODB,
    		PARTITION p1
    	VALUES
    		LESS THAN (2017) ENGINE = INNODB,
    		PARTITION p2
    	VALUES
    		LESS THAN (2018) ENGINE = INNODB,
    		PARTITION p3
    	VALUES
    		LESS THAN MAXVALUE ENGINE = INNODB
    );
    

      这样就建立了一个以 order_date 用 YEAR() 按时间的分区  我们使用查寻可以看到

    EXPLAIN PARTITIONS  SELECT * FROM st_simple_expressrecord s WHERE s.order_date BETWEEN '2019-01-13 09:57:14' AND '2019-05-13 09:57:14'
    

      

      根据时间查询只查询了 p3 这一个分区

    注意: NULL 值会使分区过滤无效

      根据上面表按照 PARITITION BY RANGE YEAR(order_date) 分区    假设所有 order_date 为 NULL 或者是一个非法值得时候 记录都会被存放到第一个分区  现在假有下面得查询 WHERE order_date BETWEEN '2018-01-01' AND '2018-02-02'  实际上他会检查 2012 年这个分区 同时他还会检查这个表得第一个分区  检查第一个分区是因为 YEAR() 函数在接收非法值得时候可能会返回 NULL 值 那么这个范围的值可能会返回 NULL 而被存放到第一个分区  这点对其他很多函数 例如 TO_DAYS() 也一样

      如果第一个分区非常大  而且扫描两个分区来查找列也不是我们使用分区的初衷  为了避免这种情况 可以创建一个无用的第一个分区 例如 上面的例子中可以使用 PARTITION p_null VALUES LESS THAN (0) 来创建第一个分区  如果插入表中的数据是有效的 那么第一个分区就是空的 这样即使需要检测第一个分区 代价也会非常小

  • 相关阅读:
    【Spark学习】Apache Spark安全机制
    【Spark学习】Apache Spark调优
    【Hadoop学习】Apache Hadoop项目简介
    【Zookeeper学习】Apache Zookeeper项目简介
    【Hadoop学习】Apache HBase项目简介
    【HBase学习】Apache HBase 参考手册 中文版
    【Spark学习】Apache Spark项目简介
    【Hadoop学习】CDH5.2安装部署
    【Zookeeper学习】Zookeeper-3.4.6安装部署
    【Spark学习】Spark 1.1.0 with CDH5.2 安装部署
  • 原文地址:https://www.cnblogs.com/shijl/p/10855482.html
Copyright © 2011-2022 走看看