MySQL基于时间字段进行分区的方案总结_MySQL
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 >= '20151207124503' and hiredate<='20151210111230'; +----+-------------+----------------+--------------+------+---------------+------+---------+------+--------+-------------+ | 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 ( '20151202' ), PARTITION p2 VALUES LESS THAN ( '20151203' ), PARTITION p3 VALUES LESS THAN ( '20151204' ), PARTITION p4 VALUES LESS THAN ( '20151205' ), PARTITION p5 VALUES LESS THAN ( '20151206' ), PARTITION p6 VALUES LESS THAN ( '20151207' ), PARTITION p7 VALUES LESS THAN ( '20151208' ), PARTITION p8 VALUES LESS THAN ( '20151209' ), PARTITION p9 VALUES LESS THAN ( '20151210' ), PARTITION p10 VALUES LESS THAN ('20151211' ) );
插入数据并查看上述查询的执行计划
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 >= '20151207124503' and hiredate<='20151210111230'; +----+-------------+---------------+--------------+------+---------------+------+---------+------+--------+-------------+ | 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 >= '20151207124503' and hiredate<='20151210111230'; +----+-------------+---------------+-------------------------------+------+---------------+------+---------+------+---------+-------------+ | 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('2015-12-02 00:00:00') ), PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-03 00:00:00') ), PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-04 00:00:00') ), PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-05 00:00:00') ), PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-06 00:00:00') ), PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-07 00:00:00') ), PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-08 00:00:00') ), PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-09 00:00:00') ), PARTITION p9 VALUES LESS THAN ( UNIX_TIMESTAMP('2015-12-10 00:00:00') ), PARTITION p10 VALUES LESS THAN (UNIX_TIMESTAMP('2015-12-11 00:00:00') ) );
插入数据并查看上述查询的执行计划
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 >= '20151207124503' and hiredate<='20151210111230'; +----+-------------+-----------------+--------------+------+---------------+------+---------+------+--------+-------------+ | 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函数进行分区,切记!

热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

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

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

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

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

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

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

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

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

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

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