第39期:MySQL 时间类分区写 SQL 注意事项

39、SQL - TOP子句的使用与优化 本文详细介绍了SQL中TOP子句的使用方法及其优化技巧,包括基本语法、排序控制、与其他SQL子句的结合以及在不同数据库系统中的实现差异。通过实际案例和性能分析,帮助开发者更好地应用TOP子句以提升查询效率和用户体验。 阅读详情

上篇《MySQL 时间类分区具体实现》介绍了时间类分区的实现方法,本篇是对上篇的一个延伸,介绍基于此类分区的相关 SQL 编写注意事项。

对于分区表的检索无非有两种,一种是带分区键,另一种则不带分区键。一般来讲检索条件带分区键则执行速度快,不带分区键则执行速度变慢。这种结论适应于大多数场景,但不能以偏概全,要针对不同的分区表定义来写最合适的 SQL 语句。用分区表的目的是为了减少 SQL 语句检索时的记录数,如果没有达到预期效果,则分区表只能带来副作用。 接下来我列举几个经典的 SQL 语句:

细心的读者在阅读完上篇可能心中就有一些疑问,基于表 ytt_p1 的 SQL 语句如下:

select count(*) from ytt_pt1 where log_date >='2018-01-01' and log_date <'2019-01-01';

同样是分区表 ytt_pt1_month1 ,基于这张表的 SQL 语句如下:

select count(*) from ytt_pt1_month1 where log_date in ('2020-01-01','2020-01-02','2020-01-03','2020-01-04','2020-01-05','2020-01-06','2020-01-07','2020-01-08','2020-01-09','2020-01-10','2020-01-11','2020-01-12','2020-01-13','2020-01-14','2020-01-15');

两张表的检索需求类似,为何写法差异不小? 后者为何要写成列表形式而不继续写成简单的范围检索形式?带着这点疑问,我们继续。

MySQL 针对分区表有一项优化技术叫 partition pruning ,翻译过来就是分区裁剪。其大致含义是 MySQL 会根据 SQL 语句的过滤条件对应的分区函数进行计算,并把计算结果穿透到底层分区表从而减小扫描记录数的一种优化策略。对于时间类型(DATE,TIMESTAMP,TIME,DATETIME),MySQL 仅支持部分函数的分区裁剪:to_days,to_seconds,year,unix_timestamp。那么我们再来看之前的疑问:表 ytt_pt1_month1 分区函数为 month ,MySQL 分区表虽然支持 month 函数,但是分区裁剪技术却不包含这个函数。 接下来,分两部分来介绍本篇内容。

第一、来体验下 MySQL 的分区裁剪技术,新建一张表 pt_pruning:分区函数为 to_days 。
create table pt_pruning (
id int,
r1 int,
r2 int,
log_date date)
partition by range(to_days(log_date))
(
PARTITION p_01 VALUES LESS THAN (to_days('2020-02-01')) ENGINE = InnoDB,
 PARTITION p_02 VALUES LESS THAN (to_days('2020-03-01')) ENGINE = InnoDB,
 PARTITION p_03 VALUES LESS THAN (to_days('2020-04-01')) ENGINE = InnoDB,
 PARTITION p_04 VALUES LESS THAN (to_days('2020-05-01')) ENGINE = InnoDB,
 PARTITION p_05 VALUES LESS THAN (to_days('2020-06-01')) ENGINE = InnoDB,
 PARTITION p_06 VALUES LESS THAN (to_days('2020-07-01')) ENGINE = InnoDB,
 PARTITION p_07 VALUES LESS THAN (to_days('2020-08-01')) ENGINE = InnoDB,
 PARTITION p_08 VALUES LESS THAN (to_days('2020-09-01')) ENGINE = InnoDB,
 PARTITION p_09 VALUES LESS THAN (to_days('2020-10-01')) ENGINE = InnoDB,
 PARTITION p_10 VALUES LESS THAN (to_days('2020-11-01')) ENGINE = InnoDB,
 PARTITION p_11 VALUES LESS THAN (to_days('2020-12-01')) ENGINE = InnoDB,
 PARTITION p_12 VALUES LESS THAN (to_days('2021-01-01')) ENGINE = InnoDB,
 PARTITION p_max VALUES LESS THAN MAXVALUE ENGINE = InnoDB
)
此表包含2020年一整年的数据,大概100W条,此处省略造数据过程。
(localhost:ytt)<mysql>select min(log_date),max(log_date),count(*) from pt_pruning;
+---------------+---------------+----------+
| min(log_date) | max(log_date) | count(*) |
+---------------+---------------+----------+
| 2020-01-02    | 2020-12-31    |  1000000 |
+---------------+---------------+----------+
1 row in set (0.72 sec)
分别执行下面几条 SQL :

SQL 1:求日期包含 ‘2020-01-02’ 的记录条数。

SQL 1: select count(*) from pt_pruning where log_date <= '2020-01-02';

SQL 2 和 SQL 3 : 求2020年1月份的记录条数。

SQL 2: select count(*) from pt_pruning where log_date < '2020-02-01';

SQL 3:  select count(*) from pt_pruning where log_date between '2020-01-01' and '2020-01-31';

SQL 1 和 SQL 2 执行时间为0.04秒,SQL 3 执行时间为0.06秒。 在没有使用索引的条件下效果还是比较理想的。

(localhost:ytt)<mysql> select count(*) from pt_pruning where log_date <= '2020-01-02';
+----------+
| count(*) |
+----------+
|     2621 |
+----------+
1 row in set (0.04 sec)

(localhost:ytt)<mysql>select count(*) from pt_pruning where log_date < '2020-02-01';
+----------+
| count(*) |
+----------+
|    82410 |
+----------+
1 row in set (0.04 sec)

(localhost:ytt)<mysql>select count(*) from pt_pruning where log_date between '2020-01-01' and '2020-01-31';
+----------+
| count(*) |
+----------+
|    82410 |
+----------+
1 row in set (0.06 sec)
所以切记使用 MySQL 分区裁剪技术规定的分区函数来建立分区表,这样写 SQL 就会相对随意些。如果由于历史原因,分区表没有使用以上规定的分区函数,可以有以下两项可能的优化策略:
  1. 手工改 SQL 语句让其达到最优。
  2. 加 HINT 来提示 MySQL 使用具体的分区。
第二、如果分区表使用的分区函数未满足 MySQL 分区裁剪技术的规则,该如何优化此类 SQL 语句?

为避免和上篇内容混淆,建张新表 pt_month,复制表 ytt_pt1_month1 的表定义。表 pt_month 和表 pt_pruning 一样,存放了2020年一整年的记录,总条数也为100W。

(localhost:ytt)<mysql>select min(log_date),max(log_date),count(*) from pt_month;
+---------------+---------------+----------+
| min(log_date) | max(log_date) | count(*) |
+---------------+---------------+----------+
| 2020-01-02    | 2020-12-31    |  1000000 |
+---------------+---------------+----------+
1 row in set (0.72 sec)

再次执行之前的三条 SQL ,并把表名替换为 pt_month :

SQL 1 执行时间为1.26秒,相比之前慢了不少。查看执行计划,发现未使用 MySQL 分区裁剪技术,扫描了不必要的表分区。(这里是全部表分区)

(localhost:ytt)<mysql>select count(*) from pt_month where log_date <= '2020-01-02';
+----------+
| count(*) |
+----------+
|     2621 |
+----------+
1 row in set (1.26 sec)

(localhost:ytt)<mysql>explain 
    -> select count(*) from pt_month where log_date <= '2020-01-02'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pt_month
   partitions: p_01,p_02,p_03,p_04,p_05,p_06,p_07,p_08,p_09,p_10,p_11,p_max
...
         rows: 992805
     filtered: 33.33
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

接下来对 SQL 1 进行一个简单的优化:既然是求日期为’2020-01-02‘ 那天的记录,那就不要使用<=来过滤,直接用=过滤:执行时间0.03秒。 查看执行计划,改后的 SQL 直接定位到表分区 p_01 ,达到了分区裁剪的效果。

(localhost:ytt)<mysql>select count(*) from pt_month where log_date = '2020-01-02';
+----------+
| count(*) |
+----------+
|     2621 |
+----------+
1 row in set (0.03 sec)

(localhost:ytt)<mysql>explain 
    -> select count(*) from pt_month where log_date = '2020-01-02'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: pt_month
   partitions: p_01
         type: ALL
...
         rows: 82522
     filtered: 10.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

继续执行 SQL 2 和 SQL 3 :执行时间都是1秒到2秒之间,效率很差,也未使用 MySQL 分区裁剪技术。

(localhost:ytt)<mysql>select count(*) from pt_month where log_date < '2020-02-01';
+----------+
| count(*) |
+----------+
|    82410 |
+----------+
1 row in set (1.35 sec)

(localhost:ytt)<mysql>select count(*) from pt_month where log_date between '2020-01-01' and '2020-01-31';
+----------+
| count(*) |
+----------+
|    82410 |
+----------+
1 row in set (1.93 sec)

来继续优化 SQL 2 和 SQL 3,由于两个需求一致,可以把范围检索改为指定列表检索:执行时间仅为0.04秒。

(localhost:ytt)<mysql>select count(*) from pt_month where log_date in ('2020-01-01','2020-01-02','2020-01-03','2020-01-04','2020-01-05','2020-01-06','2020-01-07','2020-01-08','2020-01-09','2020-01-10','2020-01-11','2020-01-12','2020-01-13','2020-01-14','2020-01-15','2020-01-16','2020-01-17','2020-01-18','2020-01-19','2020-01-20','2020-01-21','2020-01-22','2020-01-23','2020-01-24','2020-01-25','2020-01-26','2020-01-27','2020-01-28','2020-01-29','2020-01-30','2020-01-31');
+----------+
| count(*) |
+----------+
|    82410 |
+----------+
1 row in set (0.04 sec)

把范围查询改为 IN 列表后,效率得到很大提升,查询计划显示 MySQL 优化器只在分区 p_01 上检索记录。

...
   partitions: p_01
...

除了改造 SQL 语句,还可以给语句加 HINT 的方式来让 MySQL 使用分区裁剪技术:比如给 SQL 2 加上 HINT 后,执行时间为0.04秒,和之前改造后的语句执行效率相当。

(localhost:ytt)<mysql>select count(*) from pt_month partition (p_01) where log_date < '2020-02-01';
+----------+
| count(*) |
+----------+
|    82410 |
+----------+
1 row in set (0.04 sec)
总结:

如果由于历史原因分区表未使用 MySQL 分区裁剪技术,可以按照以下规则来手动对分区表进行裁剪优化:

  1. select * from tbname where partition_key = value;
  2. select * from tbname where partition_key in (value1,value2,…,valueN);
  3. 以上两种规则对于多表 JOIN 依然适用。

关于 MySQL 的技术内容,你们还有什么想知道的吗?赶紧留言告诉小编吧!

掌握mysql-connector-java-5.1.39.jar:MySQL与Java的连接桥梁 MySQL Connector/J是MySQL官方提供的Java数据库连接器,它实现了Java数据库连接(JDBC)API的规范,允许Java应用程序与MySQL数据库进行交互。作为JDBC驱动的一种,Connector/J支持标准的JDBC API,使得开发者能够使用Java代码执行SQL语句,管理事务以及处理查询结果。在Java应用程序中使用MySQL Connector/J,开发者首先需要在项目中引入Connector/J的JAR包,然后通过JDBC的连接字符串创建数据库连接。 阅读详情

相关推荐

auboi5 + d435i 使用easy handeye进行标定时,遇到相关问题记录。

解决办法:在easy_handeye默认的 calibrate.launch 文件中move group 的默认值为 "manipulator",但针对每个人的机械臂,这个值需要更改。以aubo_i5为例,需要将其改为"manipulator_i5",或者自己编写launch文件时,传入参数move group的值,便能顺利解决问题!easy_handeye_calibration_server 进程出现崩溃。

weixin_61025092的博客 958

mysql分区表:日期分区

mysql分区表:日期分区

Phillip_xian的博客 4075

C#实战:5分钟搞定西门子S7-1200 PLC数据读写(S7netplus保姆级教程)

本文详细介绍了如何使用C#和S7netplus库快速实现与西门子S7-1200 PLC的数据读写。从环境准备、连接管理到数据读写高级技巧,提供了保姆级教程和实战方案,帮助开发者绕过常见陷阱,提升工业自动化项目的开发效率。

weixin_28432777的博客 283

Mysql根据创建时间表分区实践

最近订单表遇到大数据量的问题,并且表中随着时间的积累会变得更大,当数据量较大时,存储的物理文件会变得非常大、使用性能很差。因为我的分区键(用来分区的列)没有同时存在于所有的primary key和unique key中。所以创建分区键会报错。分区键(用来分区的列)须同时存在于所有的primary key和unique key中,这是最容易出现问题。ar_sale_order_line_to_c_no_partition(为分区)ar_sale_order_line_to_c_partition(已分区)

奈斯菟咪踢呦 3539

7系列ZYNQ硬件调试:Vitis无法识别ARM DAP的排查与解决

本文详细分析了Xilinx 7系列ZYNQ芯片在Vitis开发环境中无法识别ARM DAP的常见问题及解决方案。从硬件设计检查(电源系统、时钟电路)、JTAG连接诊断到软件环境排查,提供了全面的调试指南。特别针对ARM DAP初始化失败的情况,给出了实用的排查步骤和预防措施,帮助开发者快速定位和解决类似问题。

weixin_33737134的博客 513

【大模型】大模型知识蒸馏 综述解读(Knowledge Distillation of Large Language Models)

知识蒸馏的(论文)方法总结。归纳了通过数据(如指令、对话、多模态)和训练方法(SFT、RL、数据增强),将复杂技能(如对齐、工具使用、多模态)蒸馏到开源模型的核心框架,附典型模型示例(如Alpaca、LLaVA)。

songxia928_928的博客 4334

MySQL 基于创建时间进行RANGE分区

在创建分区表之前,需要了解一下MySQL分区的基本概念。MySQL分区可以将一个大表分成多个小表,每个小表就是一个分区。常用的分区方式有:按范围分区RANGE、按列表分区LIST和按哈希分区HASH。而按照日期分区,是一种常用的按范围分区方式。在MySQL中,大量数据场景提高查询效率是非常关键的,所以,对数据表进行分区是一个很好的选择。分区的字段必须是要包含在主键当中。这时候分区的字段要么是主键,要么把分区字段加入到主键中,从而形成复合主键。首先,创建一个不分区的表。此时,会报错,含义如下。

mark_dwj的博客 1551

Elsevier期刊LaTeX双栏模板(cas-dc)实战:从Overleaf配置到投稿全流程

本文详细介绍了Elsevier期刊LaTeX双栏模板(cas-dc)在Overleaf平台上的配置与使用全流程,包括模板结构解析、标题与作者信息规范、摘要与关键词特殊格式、正文写作技巧、参考文献管理以及投稿前检查清单。特别针对Elsevier期刊投稿需求,提供了从模板安装到最终投稿的实用指南,帮助研究者高效完成论文排版工作。

weixin_28455801的博客 1323

mysql数据库分区-根据时间分区

一、数据库分区 -- 创建表 CREATE TABLE test_log ( time datetime, msg VARCHAR ( 2000 ) -- id INT NOT NULL AUTO_INCREMENT, -- PRIMARY KEY (id) ) -- 创建分区 alter table test_log partition by range columns(time)( -- 在日期之前创建分区 partition p20210801 values less than('202

c_universe的博客 8230

手眼标定搞定了,手眼矩阵不知道怎么用?快戳!!

手眼标定得到手眼矩阵到底该咋用? 大家好,我是小鱼。上几期给大家分享了关于手眼标定的方法,如果还有不清楚如何让进行手眼标定的同学可以参考下面的文章: 机器人手眼标定都能搞不定?快戳,最好用的手眼标定库!!! 很多同学做完了手眼标定之后得到了手眼矩阵,但是不知道怎么用于程序当中去,还有很多同学搞不清楚各个坐标系之间的关系,今天小智就给大家讲讲手眼矩阵的使用问题。 一、手眼矩阵为什么会长的不一样? 做完手眼标定,得到的手眼矩阵,有可能会长的不一样,这是因为旋转变换是有很多种表示方法的。 1.旋转的表

生活不止眼前的苟且 5342

第十一届全国大学生GIS应用技能大赛——广西区域发展布局示意图

我们需要制作一幅广西区域发展布局示意图,最终成图参考“数据”文件夹中的广西区域发展布局示意图.png。地图使用的投影坐标系是 Asia_North_Albers_Equal_Area_Conic,其中地理坐标系是China_Geodetic_Coordinate_System_2000,中央经线东经 105°,标准纬线是北纬 25°和北纬 47°,出图比例尺 1:4,780,000。

@HNUSTer的博客 7793

mysql数据库按日期简单分区

前段时间学着创建了一个mysql数据库,数据近千万之后性能明显下降,找到了一些简单有效的提速方法,首先是创建索引,其次就是分区表,这里记录一下分区。

Bilionn的博客 4074

MySQL分区表的局限和限制

禁止构建 分区表达式不支持以下几种构建: 存储过程,存储函数,UDFS或者插件 声明变量或者用户变量 可以参考分区不支持的SQL函数 算术和逻辑运算符 分区表达式支持+,-,*算术运算,但是不支持DIV和/运算(还存在,可以查看Bug #30188, Bug #33182)。但是,结果必须是整形或者NULL(线性分区键除外,想了解更多信息,可以查看分区类型)。 分区表

zero的小纸条 294

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

SQL使用及注意事项

SQL注意事项

Cat God 007的博客 1118

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

mysql学习教程,从入门到精通,SQL处理重复数据(39)

在数据库管理中,数据重复是一个常见的问题。重复数据可能由于多种原因产生,如数据录入错误、数据同步问题或业务逻辑上的允许等。然而,在大多数情况下,重复数据是不希望存在的,因为它们可能导致数据不一致、查询性能下降以及数据分析错误等问题。

qq_45746668的博客 1288

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

MySQL命令执行sql文件的两种方法

摘要:和其他数据库一样,MySQL也提供了命令执行sql脚本文件,方便地进行数据库、表以及数据等各种操作。下面笔者讲解MySQL执行sql文件命令的两种方法,希望能给刚开始学习MySQL数据库的朋友们。 学习过SQLServer或Oracle的朋友会知道,sql 脚本是包含一到多个 sql 命令的 sql 语句集合,我们可以将这些 sql 脚本放在一个文本文件中(我们称之为“sql 脚本文件”),然后通过相关的命令执行这个 sql 脚本文件。基本步骤如下: 1、创建 sql 脚本文件,例如...

zhangge3663的博客 3421

mysql 非法字符_关于mysql中特殊字符的使用注意事项

phpmysql转义特殊字符的函数一个是:mysql_escape_string一个是:addslashesmysql_escape_string与addslashes的区别在于mysql_escape_string总是将“’”转换成“\’”而addslashes在magic_quotes_sybase=on时将“’”转换成“””在magic_quotes_sybase=off时将“’”转换成“\...

weixin_35692051的博客 1885

SqlSugar 使用 ODBC 连接 SQL Server 2008 的注意事项

SqlSugar 使用 ODBC 连接 SQL Server 2008 的注意事项 【免费下载链接】SqlSugar DotNetNext/SqlSugar: 这是一个用于SQL Server和MySQL的ORM框架。适合用于需要简化数据库操作的场景。特点:易于使用,支持多种数据库,具有代码生成和自动映射功能。 ...

gitblog_01419的博客 447
上一篇: 故障分析 | MongoDB 5.0 报错 Illegal instruction 解决
下一篇: 故障分析 | 数据库故障 MHA 未切换
爱可生开源社区
博客等级 码龄8年 1936粉丝 1004原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值