찾다
데이터 베이스MySQL 튜토리얼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 >= &#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으로 문의하세요.
MySQL 문자열 유형 : 스토리지, 성능 및 모범 사례MySQL 문자열 유형 : 스토리지, 성능 및 모범 사례May 10, 2025 am 12:02 AM

mysqlStringTypESmpactStorageAndperformanceAsfollows : 1) charisfixed, adlaysamestoragespace.

MySQL 문자열 유형 이해 : Varchar, Text, Char 등MySQL 문자열 유형 이해 : Varchar, Text, Char 등May 10, 2025 am 12:02 AM

mysqlstringtypesincludevarchar, text, char, enum, and set.1) varcharisversatileforvariable-lengthstringsupciedlimit.2) textisidealforlargetextStorage whithoudfinedlength.3) charisfixed, witableforconsistentDatalikecodes.4)

MySQL의 문자열 데이터 유형은 무엇입니까?MySQL의 문자열 데이터 유형은 무엇입니까?May 10, 2025 am 12:01 AM

mysqloffersvariousstringdatatatypes : 1) charfixed-lengthstrings, 2) varcharforvariable-lengthtext, 3) binaryandvarbinaryforbinarydata, 4) blobandtextforlargedata 및 5) enumandsetforcontrolledInput.achtolledinput.CheachorciCificusessandperististicatististicatististics

새로운 MySQL 사용자에게 권한을 부여하는 방법새로운 MySQL 사용자에게 권한을 부여하는 방법May 09, 2025 am 12:16 AM

TograntpermissionSt

MySQL에서 사용자를 추가하는 방법 : 단계별 가이드MySQL에서 사용자를 추가하는 방법 : 단계별 가이드May 09, 2025 am 12:14 AM

ToadDuserSinMySqleFeffectially, 다음에 따르면, 다음 사항을 따르십시오

MySQL : 복잡한 권한이있는 새 사용자 추가MySQL : 복잡한 권한이있는 새 사용자 추가May 09, 2025 am 12:09 AM

toaddanewuser와 함께 complexpermissionsinmysql, followthesesteps : 1) createShereuser'NewUser '@'localhost'Identifiedby'pa ssword ';. 2) grantreadaccesstoalltablesin'mydatabase'withgrantselectonmydatabase.to'newuser'@'localhost';. 3) GrantWriteAccessto '

MySQL : 문자열 데이터 유형 및 콜라주MySQL : 문자열 데이터 유형 및 콜라주May 09, 2025 am 12:08 AM

MySQL의 문자열 데이터 유형에는 char, varchar, binary, varbinary, blob 및 텍스트가 포함됩니다. 콜라이트는 문자열의 비교와 분류를 결정합니다. 1. 차량은 고정 길이 스트링에 적합하고 Varchar는 가변 길이 스트링에 적합합니다. 2. 이진 및 바이너리는 이진 데이터에 사용되며 Blob 및 텍스트는 큰 객체 데이터에 사용됩니다. 3. UTF8MB4_UNICODE_CI와 같은 정렬 규칙은 상류 및 소문자를 무시하며 사용자 이름에 적합합니다. UTF8MB4_BIN은 사례에 민감하며 정확한 비교가 필요한 필드에 적합합니다.

MySQL : Varchars에는 몇 개의 길이를 사용해야합니까?MySQL : Varchars에는 몇 개의 길이를 사용해야합니까?May 09, 2025 am 12:06 AM

가장 좋은 mysqlvarchar 열 길이 선택은 데이터 분석을 기반으로하고, 향후 성장을 고려하고, 성능 영향을 평가하고, 문자 세트 요구 사항을 기반으로해야합니다. 1) 일반적인 길이를 결정하기 위해 데이터를 분석합니다. 2) 미래 확장 공간을 예약하십시오. 3) 성능에 대한 큰 길이의 영향에주의를 기울이십시오. 4) 문자 세트가 스토리지에 미치는 영향을 고려하십시오. 이러한 단계를 통해 데이터베이스의 효율성과 확장 성을 최적화 할 수 있습니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

SecList

SecList

SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)