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 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Douyin プラットフォームでは、多くのユーザーがレベル認定の取得を熱望しており、レベル 10 の光サインは、Douyin に対するユーザーの影響力と認知度を示しています。この記事では、ユーザーがプロセスをよりよく理解できるように、Douyin のレベル 10 ライト ボードの価格と、このレベルに到達するまでにかかる時間を詳しく掘り下げます。 1. レベル10のDouyinライトサインの価格はいくらですか? Douyinの10段階ライトサインの価格は市場の変動や需要と供給によって異なり、一般的な価格は数千元から1万元の範囲です。この価格には主に照明サイン自体の費用と、場合によってはサービス料が含まれます。ユーザーは、Douyin の公式チャネルまたはサードパーティのサービス代理店を通じてレベル 10 のライト サインを購入できますが、虚偽または詐欺的な取引を避けるために、購入する際には法的チャネルに注意する必要があります。 2. レベル 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 関数を使用して日付または時刻の書式を設定する時、分、秒を削除します。

Xiaohonshu は、生活と知識の共有に満ちたプラットフォームで、ますます多くのクリエイターが自由に意見を表現できるようになりました。小紅書でより多くの注目といいねを獲得するには、コンテンツの質に加えて、作品を公開する時期も重要です。では、Xiaohongshu が作品を公開する時間をどのように設定すればよいでしょうか? 1. 小紅書で作品を公開する時間を設定するにはどうすればよいですか? 1. ユーザーのアクティブ時間を把握する まず、小紅書ユーザーのアクティブ時間を明確にする必要があります。一般に、午後 8 時から午後 10 時までと週末の午後は、ユーザーのアクティビティが活発になる時間帯です。ただし、この期間は視聴者グループや地理などの要因によっても異なります。したがって、ユーザーのアクティブ期間をより適切に把握するには、さまざまなグループの行動習慣をより詳細に分析することをお勧めします。ユーザーの生活を理解することで

近年、Go 言語を選択する開発者がますます増えています。ただし、他のプログラミング言語と比較すると、Go 言語のコンパイル速度は十分に速くありません。多くの開発者は、Go プログラムをコンパイルするときに次の問題に遭遇します。なぜ Go プログラムのコンパイルに時間がかかるのですか?この記事では、この問題をいくつかの側面から検討します。 Go 言語のコンパイラ アーキテクチャ Go 言語のコンパイラ アーキテクチャは、フロントエンド、中間層、バックエンドの 3 段階の設計を採用しています。フロントエンドはソース コードを Go 言語の中間コードに変換する責任を負い、中間層は

Linux のファイル時間表示テクニックの詳細な説明 Linux システムでは、ファイル時間情報はファイルの管理と変更の追跡にとって非常に重要です。 Linux システムは、アクセス時間 (atime)、変更時間 (mtime)、および変更時間 (ctime) という 3 つの主要な時間属性を通じてファイル変更情報を記録します。この記事では、このファイル時間情報を表示および管理する方法について詳しく説明し、具体的なコード例を示します。 1. パラメータ -l を指定して ls コマンドを使用してファイルを一覧表示し、ファイル時間情報を確認します。
