MySQL 性能优化系列之一 单表预处理


背景介绍

我们经常在写多表关联的SQL时,会想到 left jion(左关联),right jion(右关联),inner jion(内关联)等。

但是,当表中数据量过大时,如果没有写好查询条件或者查询条件书写的先后顺序不同,可能会有明显的性能差别。

近期,有个同事遇到一个SQL查询比较慢的问题:tableA,tableB,tableC三张表联合查询的SQL,查询用时将近50s


原因分析

1、分别确认3张表的数据量

tableA:3千万+ 条记录;

tableB:5千+ 条记录;

tableC:7千+ 条记录;

2、确认SQL查询逻辑

SQL如下(查询tableA中name包含miracle,tableB中age大于岁,tableC性别为male的联合信息):

select *
from
tableA a, tableB b, tableC c
where a.id = c.id
and b.uuid = c.uuid
and a.name like '%miracle%'
and b.age > 20
and c.sex = 'male'

上述SQL的效果和内关联等价,根据SQL的关联逻辑我们可以知道,表之间关联查询,其实就是集合之间先做“笛卡尔积”,根据查询条件对这个笛卡尔积结果集再次做过滤。

可以看到,此时笛卡尔积的集合容量为:(3千万+)*(5千+)*(7千+),是一个百万亿级的庞大数据集合。

因此从这个庞大集合中,再按照过滤条件查询想要的数据,当然会慢很多。


调优方案

1、单表预处理

tableA 预处理 (处理后,tableA 中“有效”数据量级降到 1千+):

select * from tableA where name like '%miracle%'

tableB 预处理 (处理后,tableB 中“有效”数据量级降到 2千+):

select * from tableB where age > 20

tableC 预处理 (处理后,tableC 中“有效”数据量级降到 3千+):

select * from tableC where sex = 'male'

此时三张表“笛卡尔”的数据量级为:(1千+)*(2千+)*(3千+),约为 十亿级 的数据集合。相比之前,量级已经降低了十万倍

2、调整查询SQL结构

select *
from
(select * from tableA where name like '%miracle%') a,
(select * from tableB where age > 20) b,
(select * from tableC where sex = 'male') c
where a.id = c.id
and b.uuid = c.uuid

此时,SQL的查询时间为 0.14s,相比之前的50s,查询速度已经提高了几百倍

3、表关联方式转换(二次优化)

做了上面的操作,查询速度得到了明显提高。

如果我们想让查询效率更上一层楼,可以对关联方式做下调整。

由于是三张表关联,左关联和内关联在性能上还是有很大差距的。

此时三表的左关联比内关联查询性能上是提高的,SQL调整如下:

select *
from
(select * from tableA where name like '%miracle%') a
left jion
(select * from tableC where sex = 'male') c on a.id = c.id
left jion (select * from tableB where age > 20) b on b.uuid = c.uuid

此时 tableA 和 tableC 左关联的笛卡尔积集合容量为(1千+)*(2千+),是一个 百万级 的数据集合,经过 a.id = c.id 过滤后得到是一个 1千+ 的数据集合

将tableA 和 tableC 左关联后的结果集和 tableB 进行左关联,其笛卡尔积集合容量为 为(1千+)*(3千+),也是一个 百万级 的数据集合。

相比于步骤2的 十亿量级, 又降低了 1000 倍。最终,上述 SQL执行用时不到 0.1s


优化总结

对于数据表的数据量比较大的多表联合查询的场景。

SQL优化原则如下:

1、预处理单表数据,获取每张表的“有效”数据,达到首次“降级”的目的;

2、调整关联关系,实现二次“降级”。

(说明:本文说的“降级”,指的是降低SQL执行的数量级


PS:

希望能帮到大家,谢谢!

MySQL 性能优化系列之一 单表预处理的更多相关文章

  1. [MySQL性能优化系列]提高缓存命中率

    1. 背景 通常情况下,能用一条sql语句完成的查询,我们尽量不用多次查询完成.因为,查询次数越多,通信开销越大.但是,分多次查询,有可能提高缓存命中率.到底使用一个复合查询还是多个独立查询,需要根据 ...

  2. [MySQL性能优化系列]巧用索引

    1. 普通青年的索引使用方式 假设我们有一个用户表 tb_user,内容如下: name age sex jack 22 男 rose 21 女 tom 20 男 ... ... ... 执行SQL语 ...

  3. [MySQL性能优化系列]LIMIT语句优化

    1. 背景 假设有如下SQL语句: SELECT * FROM table1 LIMIT offset, rows 这是一条典型的LIMIT语句,常见的使用场景是,某些查询返回的内容特别多,而客户端处 ...

  4. MySQL性能优化(五):分表

    原文:MySQL性能优化(五):分表 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/vbi ...

  5. Mysql性能优化三(分表、增量备份、还原)

    接上篇Mysql性能优化二 对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了.如果我拆成100个表,那么每个表只有10万条记录.当然这需要数据在逻 ...

  6. MYSQL性能优化分享(分库分表)

    1.分库分表 很明显,一个主表(也就是很重要的表,例如用户表)无限制的增长势必严重影响性能,分库与分表是一个很不错的解决途径,也就是性能优化途径,现在的案例是我们有一个1000多万条记录的用户表mem ...

  7. MySQL索引优化(索引单表优化案例)

    1.单表查询优化 建表SQL CREATE TABLE IF NOT EXISTS `article` ( `id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUT ...

  8. MySQL性能优化方法二:表结构优化

    原文链接:http://isky000.com/database/mysql-perfornamce-tuning-schema 很多人都将 数据库设计范式 作为数据库表结构设计“圣经”,认为只要按照 ...

  9. [MySQL性能优化系列] 聚合索引

    1. 普通青年的索引使用方式 假设我们有一个用户表 tb_user,内容如下: name age sex jack 22 男 rose 21 女 tom 20 男 ... ... ... 执行SQL语 ...

随机推荐

  1. cas多方式登录相关知识点的总结

    知识点: cas多表单登录(在用户名,密码的基础上,增加短信验证码登录) 自定义认证策略 自定义字段添加为空校验的错误信息 Controller层接口的调用 一:场景 项目涉及到的业务是,在原cas用 ...

  2. python 判断数据类型及释疑

    Python 判断数据类型有type和isinstance 基本区别在于: type():不会认为子类是父类 isinstance():会认为子类是父类类型 class Color(object): ...

  3. VMware厚置备延迟置零,厚置备置零,精简置备详解

    1.厚置备延迟置零(zeroed thick) 以默认的厚格式创建虚拟磁盘.创建过程中为虚拟磁盘分配所需空间.创建时不会擦除物理设备上保留的任何数据,但是以后从虚拟机首次执行写操作时会按需要将其置零. ...

  4. log4j2 日志打两遍的问题

    在使用log4j2的时候,一般都需要不同的日志分类打印不同的日志等级,如下面的配置 <!-- 用于指定log4j自动重新配置的监测间隔时间,单位是秒 --> <configurati ...

  5. python+Appium自动化:屏幕截图

    屏幕截图 主要是为了程序出现错误时,开发除了可以分析日志之外,还可以进行截图更好地去定位问题. 截图一般有两种方法: 第一种save_screenshot(self,filename) driver. ...

  6. 通过LVM备份mysql数据库脚本

    #!/bin/bash #******************************************************************** #encoding -*-utf8- ...

  7. linux基础_用户管理

    1.创建用户 基本语法 创建用户:useradd [选项] 用户名 (1)当传教用户成功后,会自动的创建和用户名同名的家目录. (2)也可以通过useradd -d 指定目录 新用户名,给新创建的用户 ...

  8. 用CSS实现梯形图标

    遇到需要实现如下图标 由图形分析,梯形,平行四边形等都可以由矩形变形而来. 而想要实现梯形,需要进行3D变换,需要使用css3的 perspective属性. 属性 perspective指定了观察者 ...

  9. Go中&和*的区别

    & 返回变量的内存地址 * 返回变量的值, * 只能作用在指针上 package main import "fmt" func main() { var a = 5 var ...

  10. mybatis 多级级联(多级嵌套)

    注:笔者这里的嵌套可以用词有点欠缺,忘见谅 需求:用一个查询接口查出其结果集,这里就用伪代码标识要返回前端的类与类之间的关系. class 顶层{ String otherValue; LinkedL ...