zoukankan      html  css  js  c++  java
  • (十)RANGE分区

    ---
    title: 不懂SQL优化?那你就OUT了(十)

    MySQL如何优化-- 分区(二)-- RANGE 分区

    date: 2019-01-05

    categories: 数据库优化
    ---

    上篇博客我们讨论了分区的概述,优点和分区的类型。 这篇我们将更详细的讨论分区的类别:


    ###RANGE 分区

    按范围分区的分区方式:每个分区 包含 分区表达式值位于给定范围内的行。范围应该是连续的,而不是重叠的,并且使用 <font style='color:coral'>VALUES LESS THAN</font> 操作符来进行定义.

    案列:

    CREATE TABLE t_range_employee (
    id INT NOT NULL, -- 员工编号
    ename VARCHAR(30), -- 员工姓名
    hired DATE NOT NULL DEFAULT '1970-01-01', -- 雇佣时间
    separated DATE NOT NULL DEFAULT '9999-12-31', -- 离职时间
    job_code INT NOT NULL, -- 职位编号
    store_id INT NOT NULL -- 所在音像店编号
    )ENGINE=INNODB ;

    > 注意:
    >
    > 这里使用的t_range_employee表<span style='color:coral;font-size:20px;'>没有主键或惟一键</span>。
    >
    > 你应该记住,极有可能在实践中表是有主键,唯一键,或两者兼而有之,这使得在 选择分区列 时要取决于这些列是否有主键和唯一键, 如果有主键或则唯一键时,我们将在后面 关于分区的限制中讨论(分区键、主键和惟一键)


    根据你的需要,这个表可以有多种方式来按照范围区间进行分区。

    一种分区方案是使用store_id列进行分区。例如,可以通过添加一个<span style='color:coral;font-size:15px;'>partition by RANGE子句</span>把这个表分割成4个区间,如下所示:


    CREATE TABLE t_range_employee (
    id INT NOT NULL, -- 员工编号
    ename VARCHAR(30), -- 员工姓名
    hired DATE NOT NULL DEFAULT '1970-01-01', -- 雇佣时间
    separated DATE NOT NULL DEFAULT '9999-12-31', -- 离职时间
    job_code INT NOT NULL, -- 职位编号
    store_id INT NOT NULL -- 所在音像店编号
    ) ENGINE=INNODB
    PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN (21)
    );

    在这个范围分区方案中,存储的音像店编号为 1到5 的员工对应的所有行 存储在分区p0中,存储音像店编号6到10的员工对应的行存储在分区p1中,以此类推。每个分区都是按照从低到高的顺序定义的。这是按范围语法划分的要求; 你可以把范围分区想象成C和JAVA语言中的if...elseif…语句

    如果往表中添加一条数据:


    INSERT INTO t_range_employee VALUES(18,'张某某','2008-11-02',DEFAULT,1,15);

    此时很容易确定将这条新数据插入到分区p2中。 那么找查找这条数据时,mysql就会只在p2分区快中查找,这样效率就会快很多。


    但是此时有个问题 ?如果此时往音像店表中添加第21家商店时,会发生什么呢?




    由于t_range_employee表没有放置store_id大于20的行的分区,因此会出现错误,因为服务器不知道将其放置在何处。要避免这种错误,你可以通过在 CREATE TABLE 语句中使用 一个 “catchall” VALUES LESS THAN子句,该子句提供了将所有大于指定最大值的行放置该分区中。

    例如:


    CREATE TABLE t_range_employee (
    id INT NOT NULL, -- 员工编号
    ename VARCHAR(30), -- 员工姓名
    hired DATE NOT NULL DEFAULT '1970-01-01', -- 雇佣时间
    separated DATE NOT NULL DEFAULT '9999-12-31', -- 离职时间
    job_code INT NOT NULL, -- 职位编号
    store_id INT NOT NULL -- 所在音像店编号
    ) ENGINE=INNODB
    PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN (21),
    PARTITION p4 VALUES LESS THAN MAXVALUE
    );




    MAXVALUE 表示的整数值总是大于可能的最大整数值(在数学中,它是最小上界)。也就是说,当store_id 列值大于或等于21(定义的最大值)的任何行都存储在p4分区中,在将来的某个时候,当存储的数量增加到25、30或更多时,您可以使用ALTER TABLE语句为存储21-25、26-30等添加新的分区(有关如何做到这一点的详细信息,将会在后面的分区管理中讨论”)。

    以同样的方式,你也可以使用 job_code 来进行分区,假设两位数的编号用于普通(店内)员工,三位数编号的用于办公室和技术支持人员,四位数编号用于管理职位,您可以使用以下语句创建分区表:

    CREATE TABLE t_range_employee (
    id INT NOT NULL, -- 员工编号
    ename VARCHAR(30), -- 员工姓名
    hired DATE NOT NULL DEFAULT '1970-01-01', -- 雇佣时间
    separated DATE NOT NULL DEFAULT '9999-12-31', -- 离职时间
    job_code INT NOT NULL, -- 职位编号
    store_id INT NOT NULL -- 所在音像店编号
    ) ENGINE=INNODB
    PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)

    );

    当然您也可以在分区子句中使用表达式。但是,MySQL必须能够计算表达式的值,并且返回值作为小于(<)比较的一部分。

    例如: 使用雇佣时间来分区,把雇佣时间在2000年之前的划分到p0区,2000到2015年的划分到p1区,2015年--2020年放到p2区,其他年份的放到p3区

    CREATE TABLE t_range_employee (
    id INT NOT NULL, -- 员工编号
    ename VARCHAR(30), -- 员工姓名
    hired DATE NOT NULL DEFAULT '1970-01-01', -- 雇佣时间
    separated DATE NOT NULL DEFAULT '9999-12-31', -- 离职时间
    job_code INT NOT NULL, -- 职位编号
    store_id INT NOT NULL -- 所在音像店编号
    ) ENGINE=INNODB
    PARTITION BY RANGE (YEAR(hired)) (
    PARTITION p0 VALUES LESS THAN (2000),
    PARTITION p1 VALUES LESS THAN (2015),
    PARTITION p2 VALUES LESS THAN (2020),
    PARTITION p3 VALUES LESS THAN MAXVALUE
    );


    ####什么时候使用范围分区

    RANGE分区在如下场合特别有用:

    1. 需要删除一些旧数据的时候。

    如果你使用的是按雇佣时间来分区的方案,那么您可以简单地使用 alter table t_range_employee drop partition p0 来删除 雇佣分年在2000以前的数据。这比你执行 delete from t_range_employee where year(hired) <2000 语句的效率高很多。


    2. 想要使用一个包含有日期或时间值,或包含有从一些其他级数开始增长的值的列。


    3. 经常运行直接依赖于用于分割表的列的查询。

    例如: 当你需要执行:
    EXPLAIN SELECT COUNT(*) FROM t_range_employee WHERE separated BETWEEN '2000-01-01' AND '2000-12-31' GROUP BY store_id; MySQL可以快速确定只需要扫描分区p1,因为其余的分区不能包含任何满足WHERE子句的记录。




  • 相关阅读:
    【288】◀▶ 博客园黑色代码主题实现
    【287】◀▶ arcpy 常用类说明
    【286】◀▶ Python 内置函数说明
    LeetCode Insert Interval
    Craking the coding interview 面试题:完美随机洗牌
    遭遇多线程bug (1)
    全情投入是做好工作的基础——Leo鉴书39
    《Java 并发编程实战》读书笔记之二:图文讲述同步的另一个重要功能:内存可见性
    视图控制器
    Chapter 1. OpenGL基础回顾
  • 原文地址:https://www.cnblogs.com/ysviewvicn/p/10288367.html
Copyright © 2011-2022 走看看