首页 数据库 mysql教程 MySQL基于时间字段进行分区的方案总结_MySQL

MySQL基于时间字段进行分区的方案总结_MySQL

May 27, 2016 pm 01:46 PM
字段 方案 时间

MySQL支持的分区类型一共有四种:RANGE,LIST,HASH,KEY。其中,RANGE又可分为原生RANGE和RANGE COLUMNS,LIST分为原生LIST和LIST COLUMNS,HASH分为原生HASH和LINEAR HASH,KEY包含原生KEY和LINEAR HASH。关于这些分区之间的差别,改日另写文章进行阐述。

 

最近,碰到一个需求,要对表的时间字段(类型:datetime)基于天进行分区。于是遍历MySQL官方文档分区章节,总结如下:

 

实现方式

 

主要是以下几种:

 

1. 基于RANGE

 

2. 基于RANGE COLUMNS

 

3. 基于HASH

 

测试数据 

 

为了测试以上三种方案,特构造了100万的测试数据,放在test表中,test表只有两列:id和hiredate,其中hiredate只包含10天的数据,从2015-12-01到2015-12-10。具体信息如下:

 

mysql> show create table test\G
*************************** 1. row ***************************
       Table: test
Create Table: CREATE TABLE `test` (
  `id` int(11) DEFAULT NULL,
  `hiredate` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select min(hiredate),max(hiredate) from test;
+---------------------+---------------------+
| min(hiredate)       | max(hiredate)       |
+---------------------+---------------------+
| 2015-12-01 00:00:00 | 2015-12-10 23:59:56 |
+---------------------+---------------------+
1 row in set (0.44 sec)

mysql> select date(hiredate),count(*) from test group by date(hiredate);
+----------------+----------+
| date(hiredate) | count(*) |
+----------------+----------+
| 2015-12-01     |    99963 |
| 2015-12-02     |   100032 |
| 2015-12-03     |   100150 |
| 2015-12-04     |    99989 |
| 2015-12-05     |    99908 |
| 2015-12-06     |    99897 |
| 2015-12-07     |   100137 |
| 2015-12-08     |   100171 |
| 2015-12-09     |    99851 |
| 2015-12-10     |    99902 |
+----------------+----------+
10 rows in set (0.98 sec)
登录后复制

测试的维度

测试的维度主要从两个方面进行,

一、分区剪裁

针对特定的查询,是否能进行分区剪裁(即只查询相关的分区,而不是所有分区)

二、查询时间

鉴于该批测试数据是静止的(即没有并发进行的insert,update和delete操作),数据量也不太大,从这个维度来考量貌似意义也不是很大。

因此,重点测试第一个维度。

基于RANGE的分区方案

在这里,选用了TO_DAYS函数

CREATE TABLE range_datetime(
    id INT,
    hiredate DATETIME
)
PARTITION BY RANGE (TO_DAYS(hiredate) ) (
    PARTITION p1 VALUES LESS THAN ( TO_DAYS('20151202') ),
    PARTITION p2 VALUES LESS THAN ( TO_DAYS('20151203') ),
    PARTITION p3 VALUES LESS THAN ( TO_DAYS('20151204') ),
    PARTITION p4 VALUES LESS THAN ( TO_DAYS('20151205') ),
    PARTITION p5 VALUES LESS THAN ( TO_DAYS('20151206') ),
    PARTITION p6 VALUES LESS THAN ( TO_DAYS('20151207') ),
    PARTITION p7 VALUES LESS THAN ( TO_DAYS('20151208') ),
    PARTITION p8 VALUES LESS THAN ( TO_DAYS('20151209') ),
    PARTITION p9 VALUES LESS THAN ( TO_DAYS('20151210') ),
    PARTITION p10 VALUES LESS THAN ( TO_DAYS('20151211') )
);
登录后复制

插入数据并查看特定查询的执行计划

mysql> insert into range_datetime select * from test;                                                                    
Query OK, 1000000 rows affected (8.15 sec)
Records: 1000000  Duplicates: 0  Warnings: 0

mysql> explain partitions select * from range_datetime where hiredate >= &#39;20151207124503&#39; and hiredate<=&#39;20151210111230&#39;; 
+----+-------------+----------------+--------------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table          | partitions   | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+----------------+--------------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | range_datetime | p7,p8,p9,p10 | ALL  | NULL          | NULL | NULL    | NULL | 400061 | Using where |
+----+-------------+----------------+--------------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.03 sec)
登录后复制

注意执行计划中的partitions的内容,只查询了p7,p8,p9,p10三个分区,由此来看,使用to_days函数确实可以实现分区裁剪。

基于RANGE COLUMNS的分区方案

RANGE COLUMNS可以直接基于列,而无需像上述RANGE那种,分区的对象只能为整数。

创表语句如下:

CREATE TABLE range_columns ( 
    id INT,
    hiredate DATETIME
)
PARTITION BY RANGE COLUMNS(hiredate) (
    PARTITION p1 VALUES LESS THAN ( &#39;20151202&#39; ),
    PARTITION p2 VALUES LESS THAN ( &#39;20151203&#39; ),
    PARTITION p3 VALUES LESS THAN ( &#39;20151204&#39; ),
    PARTITION p4 VALUES LESS THAN ( &#39;20151205&#39; ),
    PARTITION p5 VALUES LESS THAN ( &#39;20151206&#39; ),
    PARTITION p6 VALUES LESS THAN ( &#39;20151207&#39; ),
    PARTITION p7 VALUES LESS THAN ( &#39;20151208&#39; ),
    PARTITION p8 VALUES LESS THAN ( &#39;20151209&#39; ),
    PARTITION p9 VALUES LESS THAN ( &#39;20151210&#39; ),
    PARTITION p10 VALUES LESS THAN (&#39;20151211&#39; )
);
登录后复制

插入数据并查看上述查询的执行计划

mysql> insert into range_columns select * from test;                                                                    
Query OK, 1000000 rows affected (9.20 sec)
Records: 1000000  Duplicates: 0  Warnings: 0

mysql> explain partitions select * from range_columns where hiredate >= &#39;20151207124503&#39; and hiredate<=&#39;20151210111230&#39;; 
+----+-------------+---------------+--------------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table         | partitions   | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+---------------+--------------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | range_columns | p7,p8,p9,p10 | ALL  | NULL          | NULL | NULL    | NULL | 400210 | Using where |
+----+-------------+---------------+--------------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.11 sec)
登录后复制

同样,使用该分区方案也实现了分区剪裁。

基于HASH的分区方案

因HASH分区对象同样只能为整数,所以我们无法像上述RANGE COLUMNS那种直接引用列,在这里,同样用了TO_DAYS函数进行转换。

创表语句如下:

CREATE TABLE hash_datetime (
   id INT,
   hiredate DATETIME
)
PARTITION BY HASH( TO_DAYS(hiredate) )
PARTITIONS 10;
登录后复制

插入数据并查看上述查询的执行计划

mysql> insert into hash_datetime select * from test;
Query OK, 1000000 rows affected (9.43 sec)
Records: 1000000  Duplicates: 0  Warnings: 0

mysql> explain partitions select * from hash_datetime where hiredate >= &#39;20151207124503&#39; and hiredate<=&#39;20151210111230&#39;;
+----+-------------+---------------+-------------------------------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table         | partitions                    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+----+-------------+---------------+-------------------------------+------+---------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | hash_datetime | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9 | ALL  | NULL          | NULL | NULL    | NULL | 1000500 | Using where |
+----+-------------+---------------+-------------------------------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)
登录后复制

不难看出,使用hash分区并不能有效的实现分区裁剪,至少在本例,基于天的需求中如此。

以上三种方案都是基于datetime的,那么,对于timestamp类型,又该如何选择呢?

事实上,MySQL提供了一种基于UNIX_TIMESTAMP函数的RANGE分区方案,而且,只能使用UNIX_TIMESTAMP函数,如果使用其它函数,譬如to_days,会报如下错误:“ERROR 1486 (HY000): Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed”。

而且官方文档中也提到“Any other expressions involving TIMESTAMP values are not permitted. (See Bug #42849.)”。

下面来测试一下基于UNIX_TIMESTAMP函数的RANGE分区方案,看其能否实现分区裁剪。

针对TIMESTAMP的分区方案

创表语句如下:

CREATE TABLE range_timestamp (
    id INT,
    hiredate TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(hiredate) ) (
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-02 00:00:00&#39;) ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-03 00:00:00&#39;) ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-04 00:00:00&#39;) ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-05 00:00:00&#39;) ),
    PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-06 00:00:00&#39;) ),
    PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-07 00:00:00&#39;) ),
    PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-08 00:00:00&#39;) ),
    PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-09 00:00:00&#39;) ),
    PARTITION p9 VALUES LESS THAN ( UNIX_TIMESTAMP(&#39;2015-12-10 00:00:00&#39;) ),
    PARTITION p10 VALUES LESS THAN (UNIX_TIMESTAMP(&#39;2015-12-11 00:00:00&#39;) )
);
登录后复制

插入数据并查看上述查询的执行计划

mysql> insert into range_timestamp select * from test;
Query OK, 1000000 rows affected (13.25 sec)
Records: 1000000  Duplicates: 0  Warnings: 0

mysql> explain partitions select * from range_timestamp where hiredate >= &#39;20151207124503&#39; and hiredate<=&#39;20151210111230&#39;;
+----+-------------+-----------------+--------------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table           | partitions   | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-----------------+--------------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | range_timestamp | p7,p8,p9,p10 | ALL  | NULL          | NULL | NULL    | NULL | 400448 | Using where |
+----+-------------+-----------------+--------------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)
登录后复制

 

同样也能实现分区裁剪。

 

 

总结:

 

1. 经过对比,个人倾向于第二种方案,即基于RANGE COLUMNS的分区实现。

 

2. 在5.7版本之前,对于DATA和DATETIME类型的列,如果要实现分区裁剪,只能使用YEAR() 和TO_DAYS()函数,在5.7版本中,又新增了TO_SECONDS()函数。

 

3. 其实LIST也能实现基于天的分区方案,但在这个需求上,相比于RANGE,还是显得很鸡肋。

 

4. TIMESTAMP类型的列,只能基于UNIX_TIMESTAMP函数进行分区,切记!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1664
14
CakePHP 教程
1423
52
Laravel 教程
1317
25
PHP教程
1268
29
C# 教程
1242
24
抖音10级灯牌多少钱?10级粉丝灯牌需要几天? 抖音10级灯牌多少钱?10级粉丝灯牌需要几天? Mar 11, 2024 pm 05:37 PM

在抖音平台上,许多用户都渴望获得等级认证,其中10级灯牌更是展示用户在抖音上的影响力和认可度。本文将深入探讨抖音10级灯牌的价格以及达到这一等级所需的时间,以帮助用户更好地了解这一过程。一、抖音10级灯牌多少钱?抖音10级灯牌的价格会受市场波动和供需情况的影响而有所差异,一般价格在几千元到万元之间。这个价格主要包括灯牌本身的成本和可能的服务费用。用户可以通过抖音官方渠道或第三方服务机构购买10级灯牌,但在购买时要留意选择合法渠道,以免遭遇虚假或欺诈交易。二、10级粉丝灯牌需要几天?达到10级灯牌

迈向可验证的 AI:形式化方法的五大挑战 迈向可验证的 AI:形式化方法的五大挑战 Apr 09, 2023 pm 02:01 PM

人工智能试图模仿人类智能的计算系统,包括人类一些与智能具有直观联系的功能,例如学习、解决问题以及理性地思考和行动。在广义地解释上,AI 一词涵盖了许多密切相关的领域如机器学习。那些大量使用 AI 的系统在医疗保健、交通运输、金融、社交网络、电子商务和教育等领域都产生了重大的社会影响。这种日益增长的社会影响,也带来了一系列风险和担忧,包括人工智能软件中的错误、网络攻击和人工智能系统安全等方面。因此,AI 系统的验证问题以及更广泛的可信 AI 的话题已经开始引起研究界的关注。“可验证 AI”已经被确

艾尔登法环通关需要多久 艾尔登法环通关需要多久 Mar 11, 2024 pm 12:50 PM

玩家在艾尔登法环中进行游戏时可以体验游戏主线剧情,以及收集游戏成就,有很多玩家不知道艾尔登法环通关需要多久,玩家的通关流程在30个小时。艾尔登法环通关需要多久答:30个小时。1、这个30个小时的通关时长指的虽然不是高手般的速通,但是也省略了很多的流程。2、如果你想获得更好的游戏体验或者是体验完整的剧情,那么时长上肯定要花费更多的时间。3、如果玩家是全收集大约要100-120小时。4、如果是只走主线刷BOSS大约:50-60小时。5、如果是想全部体验:150小时打底。

linux 可以重置系统时间吗 linux 可以重置系统时间吗 Mar 13, 2023 am 10:50 AM

linux可以重置系统时间,其重置方法是:1、使用date命令查看时间;2、使用“yum install ntp”命令安装ntp;3、通过“ntpdate -u ntp.api.bz”命令实现网络时间同步即可。

php 怎么实现时间把时分秒去掉 php 怎么实现时间把时分秒去掉 Mar 13, 2023 am 11:20 AM

php实现时间把时分秒去掉的方法:1、创建一个php示例文件;2、使用strtotime函数将日期时间转换为时间戳;3、通过date函数对日期或时间进行格式化即可去掉时分秒。

小红书发布作品时间怎么设置?发布作品时间准确吗? 小红书发布作品时间怎么设置?发布作品时间准确吗? Mar 24, 2024 pm 01:31 PM

小红书,一个充满生活气息与知识分享的平台,让越来越多的创作者在此畅所欲言。要想在小红书上获得更多的关注和点赞,除了内容质量之外,发布作品的时间也是至关重要的。那么,如何设置小红书发布作品的时间呢?一、小红书发布作品时间怎么设置?1.了解用户活跃时间首先,需要明确小红书用户的活跃时间。通常来说,晚上8点到10点以及周末下午是用户活跃度较高的时段。然而,这个时间段也会受到受众群体和地域等因素的影响而有所不同。因此,为了更好地把握用户活跃时段,建议对不同群体的行为习惯进行更详细的分析。通过了解用户的活

为什么我的Go程序需要更长的时间来编译? 为什么我的Go程序需要更长的时间来编译? Jun 09, 2023 pm 06:00 PM

近年来,Go语言已经成为了越来越多开发者的选择。但是,相比其他编程语言而言,Go语言的编译速度却不够快。很多开发者在编译Go程序时都会遇到这样的问题:为什么我的Go程序需要更长时间来编译?本文将会从几个方面探讨这个问题。Go语言的编译器架构Go语言的编译器架构采用的是三阶段设计,分别是前端、中间层和后端。前端负责将源代码翻译成Go语言的中间代码,中间层则将中

Linux 文件时间查看技巧详解 Linux 文件时间查看技巧详解 Feb 21, 2024 pm 01:15 PM

Linux文件时间查看技巧详解在Linux系统中,文件的时间信息对于文件管理和跟踪变更非常重要。Linux系统通过三种主要时间属性来记录文件的变更信息,分别是访问时间(atime)、修改时间(mtime)和更改时间(ctime)。本文将详细介绍如何查看和管理这些文件时间信息,并提供具体的代码示例。1.查看文件时间信息通过使用ls命令结合参数-l可以列出文

See all articles