MySQL高级特性

发布于 2019-06-21 · 本文总共 4571 字 · 阅读大约需要 14 分钟

分区表

主要目的是将数据按照一个较粗的粒度分在不同的表中;

分区表是一个独立的逻辑表,但是底层由多个物理子表组成;

实现分区的代码实际上是对一组底层表的句柄对象的封装; 分区表对于SQL层来说是一个完全封装底层实现的黑盒子,对应用透明;

在底层文件系统,每一个分区表都有一个使用#命名的表文件;

mysql> CREATE TABLE `table_partition` (
    ->   `ftime` datetime NOT NULL,
    ->   `c` int(11) DEFAULT NULL,
    ->   KEY (`ftime`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    -> PARTITION BY RANGE (YEAR(ftime))
    -> (PARTITION p_2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
    ->  PARTITION p_2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
    ->  PARTITION p_2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
    -> PARTITION p_others VALUES LESS THAN MAXVALUE ENGINE = InnoDB);
Query OK, 0 rows affected (0.13 sec)

ls -lh  /usr/local/mysql/data/db_test
total 7584
-rw-r-----  1 _mysql  _mysql   128K  6 23 15:43 table_partition#P#p_2017.ibd
-rw-r-----  1 _mysql  _mysql   128K  6 23 15:43 table_partition#P#p_2018.ibd
-rw-r-----  1 _mysql  _mysql   128K  6 23 15:43 table_partition#P#p_2019.ibd
-rw-r-----  1 _mysql  _mysql   128K  6 23 15:43 table_partition#P#p_others.ibd

MySQL在创建时使用Partition by子语句定义每个分区存放的数据; 在执行查询时,优化器会根据分区定义过滤分区,查询只需要查找包含重要数据的分区就可以了;

适用场景:

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

2.分区表数据更容易维护;方便清除整个分区,可以对一个独立分区进行优化、检查、修复等操作;

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

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

5.可以备份和恢复独立的分区,在大数据集的场景有用;

限制:

1.一个表最多只能有1024个分区;

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

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

原理

从存储引擎的角度来看,底层表和一个普通表没有任何不同,存储引擎也无须知道这是一个普通表还是一个分区表的一部分;

  • select查询

查询分区时,分区层先打开并锁定所有底层表,优化器先判断是否可以过滤部分分区,然后再调用对应的存储引擎接口访问各个分区的数据;

insert、delete、update操作也都会“先打开并锁住所有的底层表”;

分区表的类型

如何使用

在数据量超大的时候,B-Tree索引就无法起作用了,除非是索引覆盖查询;否则数据库服务器需要根据索引扫描的结果回表,查询所有符合条件的记录; 如果数据量巨大,将产生大量随机IO;随之,数据库的响应时间将大到不可接受的程度;

为了保证大量数据的可扩展性,一般有两种策略:

1.全量扫描数据, 不要任何索引;

2.索引数据,并分离热点 如果数据有明显的热点,并且除了这部分数据,其他数据很少被访问到,可以将这部分数据单独放在一个分区

可能的问题

1.NULL值会使分区过滤无效;

2.分区列和索引列不匹配

3.选择分区的成本可能很高;

4.打开并锁住所有底层表的成本可能很高;

5.维护分区的成本可能很高

分区实现中的一些限制:

1.所有分区都必须使用相同的存储引擎;

2.分区函数可以使用的函数和表达式有限;

3.有些存储引擎不支持分区;

4.对于MyISAM表,使用分区时需要打开更多的文件描述符;

5.对于MyISAM分区表,不能再使用load_index_into_cache操作;

查询优化

分区最大的优势就是优化器可以根据分区函数来过滤一些分区;

所以对于访问分区表,在where条件中带入分区列很重要;

只能在使用分区函数的列本身进行比较才能过滤分区,而不能根据表达式的值去过滤分区,即使这个表达式就是分区函数也不行;

mysql> explain select * from table_partition where ftime='2018-12-1';
+----+-------------+-----------------+------------+------+---------------+-------+---------+-------+------+----------+-------+
| id | select_type | table           | partitions | type | possible_keys | key   | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------------+------------+------+---------------+-------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | table_partition | p_2019     | ref  | ftime         | ftime | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-----------------+------------+------+---------------+-------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)


mysql> explain select * from table_partition where YEAR(ftime)='2018';
+----+-------------+-----------------+-------------------------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table           | partitions                    | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------------+-------------------------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | table_partition | p_2017,p_2018,p_2019,p_others | ALL  | NULL          | NULL | NULL    | NULL |    2 |   100.00 | Using where |
+----+-------------+-----------------+-------------------------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

不能根据表达式的值去过滤分区:

mysql> explain select * from table_partition where YEAR(ftime)='2018'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: table_partition
   partitions: p_2017,p_2018,p_2019,p_others
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

合并表

一种早期的、简单的分区实现;将被淘汰的技术;

允许用户单独访问各个子表;分区表和优化器的结合更紧密;

视图

5.0版本之后引入;

视图本身是一个虚拟表,不存放任何数据,在使用SQL语句访问视图的时候,它返回的数据是MySQL从其他表生成的;

可更新视图

可以通过更新视图来更新视图涉及的相关表;

1.如果视图定义中包含了GROUP BY、UNION、聚合函数。以及其他特殊情况,就不能被更新了;

2.使用临时表算法实现的视图也无法被更新;

视图对性能的影响

在MySQL中某些情况下视图也可以帮助提升性能; 并且视图还可以和其他提升性能的方式叠加使用;

视图的限制

MySQL还不支持物化视图;

物化视图:将视图结果数据存放在一个可以查看的表中,并定期从原始表中刷新数据到这个表中;

MySQL也不支持在视图中创建索引;

外键约束

InnoDB是目前MySQL唯一支持外键的内置存储器;

如果只是使用外键做约束,通常在应用程序中实现该约束会更好;

外键会带来很大的额外消耗;

在MySQL内部存储代码

MySQL允许通过触发器、存储过程、函数的形式来存储代码;

优点:

1.在服务器内部执行,离数据最近,节省带宽和网络延迟;

2.代码重用;

3.简化代码的维护和版本更新;

4.提升安全,比如更细粒度的权限控制;

5.服务器端可以缓存存储过程的执行计划,对于反复调用的过程会大大降低消耗;

6.备份和维护都可以在服务器端完成;所以存储程序的维护工作会很简单;

7.在应用开发和数据库开发人员之间更好的分工;

缺点:

1.MySQL编写存储代码比其他数据库更难;

2.相对程序的代码,存储代码效率要差一点;存储代码可用的函数非常有限;

3.给应用程序代码的部署带来额外的复杂性;

4.安全隐患;非标准的加密功能放在存储程序时;

5.给数据库服务器增加额外的压力;

6.MySQL并没有什么选项可以控制存储程序的资源消耗;

7.调试MySQL存储过程比较困难;

存储过程和函数

触发器

事件

MySQL5.1引入的一种新的存储代码的方式;类似于Linux的定时任务,不过是完全在MySQL内部实现的;

在存储程序中保留注释

使用版本相关的注释;

游标

绑定变量

用户自定义函数

字符集和校对

全文索引

查询缓存

分布式事务




本博客所有文章采用的授权方式为 自由转载-非商用-非衍生-保持署名 ,转载请务必注明出处,谢谢。
声明:
本博客欢迎转发,但请保留原作者信息!
博客地址:邱文奇(qiuwenqi)的博客;
内容系本人学习、研究和总结,如有雷同,实属荣幸!
阅读次数:

文章评论

comments powered by Disqus


章节列表