zoukankan      html  css  js  c++  java
  • MySQL分区总结

     

    前言:分区是指根据一定的规则,数据库把一个表分解成多个更小的,更容易管理的部分。分区对应用来说是完全透明的,不影响应用的业务逻辑。

    MySQL分区的优点:

      1、和单个磁盘或者文件系统分区相比,可以存储更多数据;

      2、优化查询。在Where字句中包含分区条件时,可以只扫描必要的一个或多个分区来提高查询效率;同时在涉及 SUM() 和 COUNT() 等聚合函数的查询时,可以容易地在每个分区上并行处理,最终只需要汇总所有分区得到的结果。

      3、对于已经过期或者不需要保存的数据,可以通过删除与这些数据有关的分区来快速删除数据。

      4、跨多个磁盘来分散数据查询,以获得更大的查询吞吐量。

    一:概述

    MySQL 支持使用大部分存储引擎(如:MyISAM、InnoDB、Memory等)创建分区表,不支持使用MERGE和CSV。 

    MySQL分区类型主要包括:range分区、list分区、hash分区、key分区;

    无论是那种MySQL分区类型,要么分区表上没有主键/唯一键,要么分区表的主键/唯一键都必须包含分区键,也就是说不能使用主键/唯一键字段之外的其他字段分区

    如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    mysql> create table emp(
        ->     id int not null,
        ->     ename varchar(30),
        ->     hired date not null default '1970-01-01',
        ->     separated date not null default '9999-12-31',
        ->     job varchar(30) not null,
        ->     store_id int not null,
        ->     primary key(id)
        -> )
        -> partition by range (store_id) (
        ->     partition p0 values less than(10),
        ->     partition p1 values less than(20),
        ->     partition p2 values less than(30)
        -> );
    ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

      去掉主键约束后,创建表会成功:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mysql> create table emp(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null
        -> )
        -> partition by range (store_id) (
        -> partition p0 values less than(10),
        -> partition p1 values less than(20),
        -> partition p2 values less than(30)
        -> );
    Query OK, 0 rows affected (0.02 sec)

      分区的名字遵循MySQL标识符的原则。分区的名字不区分大小写,如果分区名分别为 mypart 和 MyPart 将会被MySQL认为是同一个分区而报错。

    二:RANGE分区

      按照range分区的表是利用取值范围将数据分区,区间要连续并且不能互相重叠,使用 values less than 操作符进行分区定义。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mysql> create table emp(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null
        -> )
        -> partition by range (store_id) (
        -> partition p0 values less than(10),
        -> partition p1 values less than(20),
        -> partition p2 values less than(30)
        -> );
    Query OK, 0 rows affected (0.02 sec)

      如果增加商店ID大于等于30的行,超出分区范围,会出现错误。

    1
    2
    mysql> insert into emp(id,ename,hired,job,store_id) values ('7934''MILLER''1982-01-23''CLERK', 50);
    ERROR 1526 (HY000): Table has no partition for value 50

      可以使用 values less than maxvalue 设置分区,超出明确指定的分区值时,数据会存储在该分区,如:

    1
    2
    3
    4
    5
    6
    mysql> alter table emp add partition(partition p3 values less than maxvalue);
    Query OK, 0 rows affected (0.25 sec)
    Records: 0  Duplicates: 0  Warnings: 0
     
    mysql> insert into emp(id,ename,hired,job,store_id) values ('7934''MILLER''1982-01-23''CLERK', 50);
    Query OK, 1 row affected (0.05 sec)

      MySQL支持在 values less than 字句中使用表达式 partition by range (year(separated)),可自行测试。类似的函数有 to_days()、to_seconds();5.5版本后可直接使用日期字段作为分区键。

    Range分区特别使用的两种情况:

      1、当需要删除过期的数据时,只需要简单的 ALTER TABLE emp DROP PARTITION p0 来删除p0分区中的数据,对于具有上百万条记录的表来说,删除分区要比运行一个 DELETE 语句有效得多。

      2、经常运行包含分区间的查询,MySQL 可以很快地确定只有一个或者某些分区需要扫描,因为其他分区不可能包含有该 WHERE 字句的任何记录。

    三:List 分区

      List 分区是建立离散的值列表告诉数据库特定的值属于哪个分区,List 分区在很多方面类似于 Range 分区,区别在于 List 分区是从属于一个枚举列表的值得集合,Range 分区从属于一个连续区间值得集合。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    mysql> create table expenses(
        -> expense_date date not null,
        -> category int,
        -> amount decimal (10,3)
        -> )partition by list(category) (
        -> partition p0 values in (3, 5),
        -> partition p1 values in (1, 10),
        -> partition p2 values in (4, 9),
        -> partition p3 values in (2),
        -> partition p4 values in (6)
        -> );
    Query OK, 0 rows affected (0.05 sec)

      如果插入的列值不包含分区值得列表中,insert 操作会失败报错。注意:List 分区不存在类似 values less than maxvalue 这样包含其他值在内的定义方式。将要匹配的任何值都必须在值列表中。

    四:Hash 分区

      Hash 分区主要用来分散热点读,确保数据在预先确定个数的分区中尽可能平均分布。MySQL 支持两种 Hash 分区:常规 Hash 分区、线性 Hash 分区(Linear Hash 分区)。常规 Hash 分区使用的是取模算法,线性 Hash 分区使用的是一个线性的2的幂的运算法则。

    1、常规 Hash 分区

      使用 PARTITION BY HASH(expr) PARTITIONS num 字句对分区类型、分区键和分区个数进行定义,其中 expr 是某列值或一个基于某列值返回的表达式。num 是一个非负整数,表示分区数量,默认为1。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> create table emp_hash(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null
        -> )
        -> partition by hash (store_id) partitions 4;
    Query OK, 0 rows affected (0.03 sec)

      假设将要保存记录的分区编号为N, 那么 N=MOD(expr, num) 如,emp_hash表中有4个分区,插入一个 store_id列值为234的记录到表中:

    1
    2
    mysql> insert into emp_hash values (1, 'Tom''2010-10-10''9999-12-31''Clerk', 234);
    Query OK, 1 row affected (0.01 sec)

      MOD(234, 4)=2 保存这条记录的分区应该是p2;从p0 开始,模为 0 时保存到 p0 依次类推。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mysql> explain partitions select from emp_hash where store_id =234G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: emp_hash
       partitions: p2
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 2
            Extra: Using where
    1 row in set (0.05 sec)

      不推荐使用涉及多列的哈希表达式,复杂的表达式可能会引起性能问题。常规 Hash 在分区管理上需要的代价高,不适合需要灵活变动分区的需求。

    2、线性 Hash 分区(Linear Hash)

      线性 Hash 分区和常规 Hash 分区 在语法上的唯一区别是在 partition by 字句中添加关键字 “Linear”,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> create table emp_linear(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null
        -> )
        -> partition by linear hash (store_id) partitions 4;
    Query OK, 0 rows affected (0.03 sec)

      线性Hash分区的优点是:在分区维护(增加、删除、合并、拆分分区时),MySQL能够处理得更加迅速;缺点是:对比常规的Hash分区(取模)的时候,线性Hash各个分区之间数据的分布不太均衡。

    五:Key 分区

      Key 分区类似于 Hash 分区,不过 Key 分区不允许使用用户自定义的表达式,需要使用 MySQL 服务器提供的 Hash 函数;同时 Hash 分区只支持整数分区,而 Key 分区支持使用 Blob 或 Text 类型外其他类型的列作为分区键

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> create table emp_key(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null
        -> )
        -> partition by key (job) partitions 4;
    Query OK, 0 rows affected (0.05 sec)

      创建 Key 分区表的时候,可以不指定分区键,默认会首先选择使用主键作为分区键

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mysql> create table emp_key1(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null
        -> )
        -> partition by key () partitions 4;
    Query OK, 0 rows affected (0.03 sec)

      在没有主键的情况,会选择非空唯一键作为分区键,分区键的唯一键必须是非空的,如果不是非空会报错:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    mysql> create table emp_key2(
        -> id int not null,
        -> ename varchar(30),
        -> hired date not null default '1970-01-01',
        -> separated date not null default '9999-12-31',
        -> job varchar(30) not null,
        -> store_id int not null,
        -> unique key(id)
        -> )
        -> partition by key () partitions 4;
    Query OK, 0 rows affected (0.03 sec)

      和 Hash 分区类似,在 Key 分区中使用关键字 Linear 具有同样的作用,Linear Key 分区时,分区的编号是通过2的幂算法得到的,不是通过取模得到的。

    附:MySQL 分区的 null 值处理

      1、MySQL 分区不禁止在分区键值上使用 null 

      2、Range 分区中,null 值会被当做最小值来处理

      3、List 分区中,null 值必须出现在枚举列表中,否则不被接受

      4、Hash/Key 分区中,null 值会被当做零值来处理

      5、为了避免在处理 null 值时出现误判,推荐通过设置字段非空和默认值来绕开 MySQL 对 null 值的默认处理

  • 相关阅读:
    C#--web中上传图片与浏览
    win通过ssh访问virtualbox虚拟中的debian
    【转】win10中下载安装mysql5.7
    [转发]centos7利用crontab定时检测杀死cpu使用率超过80%的进程
    MySQL 重要参数 innodb_flush_log_at_trx_commit 和 sync_binlog
    查询正在执行的sql语句
    php图片等比例缩放
    excel 导入 sqlserver 字符串被截取为255长度解决方案
    查询阻塞的sql
    centos7安装mariadb10遇到的问题解决
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/14010812.html
Copyright © 2011-2022 走看看