多表联查优化

2023-10-27

多表联查优化我总结有以下几点

  • 优化sql语句
  • 索引优化
  • 反范式设计
  • 业务代码优化
  • 使用缓存

优化sql语句

sql性能分析

查看执行频次

---查看执行频次(select,insert,delete,update)
		shwo global|session status like ‘Com_______’;
		注意:global是全局,session是当前会话,七个_

慢查询日志

满查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10)的所有sql语句的日志。mysql的慢查询日志默认没有开启,需要改配置文件(/etc/my.cnf)中配置一下信息     
     
     #开启mysql慢日志查询的开关
     slow_query_log=1
     #设置慢日志的时间为2秒,sql语句执行时间超过2秒,就会记录在慢日志里
     long_query_time=2

配置完毕后,重启mysql:systemctl restart mysqld.service 查看慢日志:/var/lib/mysql/localhost-slow.log

 --查看是否开启慢日志
     Show variables like 'slow_query%';
 --查看慢日志
     cat /var/lib/mysql/localhost-slow.log 
     注意:这里的文件名是不确定的,需要第一步命令查看慢文件存放位置:slow_query_log_file的值

查询profile

慢查询只能查到大于预设值的语句,并且不能查看每条语句的耗时情况

 --查询mysql是否支持profile查询
     select @@have_profiling
 --查询profile是否开启
     select @@profiling
 --开启profile
     set global/session profiling=1;
 --查看profile
     show profiles;
 --查看profile指定语句
     show profile for query 查询id;
 --查看profile指定语句附带cpu使用情况
     show profile cpu for query 查询id;

查看explain执行计划

可以查看是否用到索引,表的连接情况等信息

 --查看explain执行计划
     explain/desc 查询语句
 各字段含义:
     id:操作表的顺序(id相同,从上往下依次,id不同,值越大,越先执行)
     select_type:表示select的类型,常见的有simple(简单表,不使用表连接或者子查询),primary(主查询,外层的查询),union(联合查询的第二个或者后面的查询),subquery(select/where之后包含了子查询)
     type:性能由好到差为:null,system,const,eq_ref,ref,range,index,all。system为查询系统变量,const为查询主键或唯一索引,ref:用了辅助索引,index:用了索引但对索引全表扫描,all:全表扫描
     possiable_key:可能用到的索引
     key:实际用到的索引,为null则没有用到索引
     key_len:索引使用的字节数,越小越好,和值有关系
     rows:必须查询的行数
     filtered:返回结果占需要读取的行数的百分比,100为最好
     Extre:额外信息

orderby优化

使用explain可以查看语句执行过程

①.Using filesort:通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫FileSort排序。
②.Using index:通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高。

注意:当orderby的多字段同时升序或降序走索引,不同走缓冲区,但是如果没有索引或者只有一个,不好意思,回表扫描,得到完整数据再放过缓冲区

优化原则

  1. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
  2. 尽量使用覆盖索引。
  3. 多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。
  4. create index 索引名 on 表名(列 desc,列 asc);
  5. 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sortbuffer_size(默认256k)因为如果超过了这个值,会在磁盘文件中排序,效率低

groupby优化

  1. 分组操作时,可以通过索引来提高效率
  2. 分组操作时,索引的使用也是满足最左前缀法则的。

limit优化

在大数据量下分页查询,limit 2000000,10中第一个参数越大,耗时越长。此时查询需要2000010行,但返回只有10行,2000000行被丢弃了

  1. 一般分页查询时,通过创建 覆盖索引 能够提高性能,可以通过覆盖索引加子查询形式进行优化
  2. 在in的子查询中不能有limit,可以把子查询的语句当成一张表来多表查询

count优化

  1. 自己计数,可以通过redis维护总数
  2. count(*)>count(1)>count(主键)>count(字段)

索引优化

索引使用

--最左法则
		联合查询中,索引最左边的必须存在,并且不能跳过中间某一列,否则后面的索引列失效
--范围查询
		联合查询中,不能出现(>,<)可以使用<=,>=,否则后面的索引失效
--索引列运算
		不要在索引列上运算,比如字符串操作函数,否则索引失效
--字符串不加引号
		字符串类型列查询不加引号导致索引失效
--模糊匹配
		模糊查询后面模糊不失效,前面模糊失效
--or连接的条件
		or连接的条件,如果俩边都有索引,则有效,只要一边没有则失效,可以对没有索引的创建索引
--数据分布影响
		如果mysql评估全表扫描比索引还快,不会走索引,会全表扫描
--SQL提示
		SQL提示是优化数据库的重要手段,在sql语句中插入一些人为你的提示来优化,比如有多个索引,可以指定使用哪个索引
		use index :建议数据库使用,但数据库评估后如果不满意,可能不会采纳		
		ignore index:直接忽略
		force index:强制使用
		select * from 表名 use/ignore/force index(索引名) where 条件;
--覆盖索引
		当select 列中所有返回的列都能在索引中找到,最优,如果找不到需要回表查找聚集索引,性能相对低一点,所以尽量避免select *,对语句优化,需要同时照顾select查询的列
--前缀索引
		如果一个字段内容比较大,可以根据前缀创建前缀索引
		create index 索引名字 on 表名(列名(前缀个数));
    
    前缀个数取值问题:
    当索引选择性越高越好,如唯一索引选择性为1,可以通过
    select count(distinct substring(字段,1,前缀个数))/count(*) from 表 where 条件
    前缀个数越少越好,选择性越高越好,综合选取
--单列索引和联合索引
		如果条件是多个字段,推荐使用联合索引,因为不需要回表查询

索引设计原则

1. 针对于数据量较大,且查询比较频繁的表建立索引。
2. 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
4. 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
7. 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。否则导致引擎放弃使用索引而进行全表扫描,非要使用null,可以在null上设置默认值0,确保表中num列没有null值
8. 尽量使用数字类型字段,若只含数值信息的字段,尽量不要设计为字符型,这样会降低查询和连接的性能,并会增加存储开销,这是因为引擎在处理查询和连接时,会逐个比较字符串中每一个字符。而对于数字型而言,只需要对比一次就可以了。
9. 对于子查询慎用 in,可以将子查询当成一张表连接查询,覆盖索引+连接查询

多表中索引使用规则

  1. from和join,选择join
  2. left join的驱动表是左边,小表驱动大表,不过mysql优化器有优化,自动将结果集小的当驱动表
  3. 创建外键索引,如果中间表多个字段用到条件上,可以把多个外键建立联合索引

反范式设计

范式是减少数据冗余节省磁盘的,但是现在磁盘已经不值钱了,可以针对业务设计表,增加查询条件的冗余字段,尽量减少关联查询,以空间换时间

业务代码优化

  1. 业务尽量分化,将接口拆分成多个接口
  2. 减少无用字段的返回和查询
  3. 查询条件,结果集的处理不在数据库中加工,而在业务层加工

使用缓存

使用缓存来处理是一种取巧行为,能切实处理慢查询的问题,但同时也有局限性

  • 当项目是单结点部署时,使用本地缓存
  • 当项目是多结点部署时,使用分布式缓存
  • 当然也可以使用多级缓存(不介绍)

本地缓存

这里介绍本地缓存中的Caffeine的原生使用和注解使用

导入坐标

        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.3.10.RELEASE</version>
        </dependency>

基础用法

    @Test
    public void Test2(){
        //创建Cache
        Cache<String,String> cache = Caffeine.newBuilder().build();
        //存放key/value
        cache.put("name","xuxin");
        //存在取出value,不存在取出null
        String name1 = cache.getIfPresent("name3");
        //存在取出value,不存在走数据库业务逻辑
        String name2 = cache.get("name2", key -> {
            //数据库读数据
            return "asd";
        });
        System.out.println(name1);
        System.out.println(name2);
    }

注解使用

额外添加配置文件

@Configuration
@EnableCaching //开启缓存
public class Caffeineconfig {
    /**
     * 配置缓存管理器
     * @return 缓存管理器
     */
    @Bean("caffeineCacheManager")
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                // 最后一次写入后经过固定时间过期12小时
                .expireAfterWrite(12, TimeUnit.HOURS)
                // 初始的缓存空间大小
                .initialCapacity(100)
                // 缓存的最大条数
                .maximumSize(1000));
        return cacheManager;
    }
}

在业务代码上添加注解

@Cacheable(value = "mapRendering", key = "#reqVO")
public Object mapRendering(MapRenderingReqVO2 reqVO) {
        ResultBody resultBody = new ResultBody();
        Map<String, Map> result = new HashMap<>();
        ....
        return resultBody;
}

注解使用说明

使用注解会自动按照入参把结果集封装进缓存,key为入参,value为结果集

分布式缓存

这里介绍redis

安装

进入官网下载安装:https://redis.io/

导入坐标

        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--连接池依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!--序列化-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

yml添加配置

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    lettuce:
      pool:
        max-wait: 100
        min-idle: 0
        max-idle: 8
        max-active: 8

在业务里注入客户端并使用

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void Test(){
        User user = new User("xuxin","123");
        String s = JSON.toJSONString(user);
        stringRedisTemplate.opsForValue().set("user2",s);
        String namexx = stringRedisTemplate.opsForValue().get("user");
        User user1 = JSON.parseObject(namexx, User.class);
        System.out.println(user1);
    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多表联查优化 的相关文章

  • 无法在 Android 10 中创建目录

    我无法在 android 10 中创建目录 它可以在 android Oreo 之前的设备上运行 我尝试了两种创建文件夹的方法 Using File mkdir File f new File Environment getExternal
  • 具有更高可见性的重写方法是良好的实践吗?

    回答这个问题 如何使用 GUI 使用 PaintComponent 初始化 GUI 然后添加基于鼠标的 GUI https stackoverflow com questions 21336141 how to gui using pain
  • 清理码头 - 删除“不必要”的东西

    我习惯用Jetty http jetty codehaus org jetty 作为我的网络容器 我对我做了什么安装步骤得到原始的焦油球并且清理一些目录和文件从中 我在这里想提出的是 您通常从 Jetty 中删除什么以在生产 登台环境中使用
  • 将 jar 作为 Linux 服务运行 - init.d 脚本在启动应用程序时卡住

    我目前正在致力于在 Linux VM 上实现一个可运行的 jar 作为后台服务 我已经使用了找到的例子here https gist github com shirish4you 5089019作为工作的基础 并将 start 方法修改为
  • 使用 GWT CellTableBuilder 构建树表

    Is it possible to build a tree table like this http www sencha com examples ExamplePlace basictreegrid with the new Cell
  • 使用cameltestsupport进行Camel单元测试,模板始终为空

    我正在用 Camel 做一个简单的单元测试 我想做的就是从文件 在资源下 读取 JSON 内容 将其发送到 Java 类进行验证 这是我试图测试的路线 无论我做什么 模板 我用来发送正文 json 始终为空 这是我的代码 public cl
  • Java:使用 HttpURLConnection 的 HTTP PUT

    如何执行 HTTP PUT 我正在使用的类似乎认为它正在执行 PUT 但端点将其视为我执行了 GET 我做错了什么吗 URL url new URL https HttpURLConnection conn HttpURLConnectio
  • 在文本文件中搜索单词并返回其频率

    如何在包含单词文本的文本文件中搜索特定单词并返回其频率或出现次数 使用扫描仪 String text Question how to search for a particular word in a text file containin
  • Java套接字:在连接被拒绝异常时重试的最佳方法?

    现在我正在这样做 while true try SocketAddress sockaddr new InetSocketAddress ivDestIP ivDestPort downloadSock new Socket downloa
  • 在 HTTP 标头中发送 UTF-8 值会导致 Mojibake

    我想使用 servlet 发送阿拉伯语数据HTTPServletResponse给客户 我正在尝试这个 response setCharacterEncoding UTF 8 response setHeader Info arabicWo
  • Firestore - RecycleView - 图像持有者

    我不知道如何编写图像的支架 我已经设置了 2 个文本 但我不知道图像的支架应该是什么样子 你能帮我告诉我图像的文字应该是什么样子才能正确显示吗 holder artistImage setImageResource model getArt
  • 主线程如何在该线程之前运行?

    我有以下代码 public class Derived implements Runnable private int num public synchronized void setA int num try Thread sleep 1
  • 在java中实现你自己的阻塞队列

    我知道这个问题之前已经被问过并回答过很多次了 但我只是无法根据互联网上找到的示例找出窍门 例如this http tutorials jenkov com java concurrency blocking queues html or t
  • Java - 返回值是否会中断循环?

    我正在编写一些基本上遵循以下格式的代码 public static boolean isIncluded E element Node
  • Spring Security OAuth2简单配置

    我有一个简单的项目 需要以下简单的配置 我有一个 密码 grant type 这意味着我可以提交用户名 密码 用户在登录表单中输入 并在成功时获得 access token 有了该 access token 我就可以请求 API 并获取用户
  • Dispatcher-servlet 无法映射到 websocket 请求

    我正在开发一个以Spring为主要框架的Java web应用程序 特别使用Spring core Spring mvc Spring security Spring data Spring websocket 像这样在 Spring 上下文
  • 解决错误javax.mail.AuthenticationFailedException

    我不熟悉java中发送邮件的这个功能 我在发送电子邮件重置密码时遇到错误 希望你能给我一个解决方案 下面是我的代码 public synchronized static boolean sendMailAdvance String emai
  • 如何在Java中正确删除数组[重复]

    这个问题在这里已经有答案了 我刚接触 Java 4 天 从我搜索过的教程来看 讲师们花费了大量精力来解释如何分配二维数组 例如 如下所示 Foo fooArray new Foo 2 3 但我还没有找到任何解释如何删除它们的信息 从内存的情
  • 哪个集合更适合存储多维数组中的数据?

    我有一个multi dimensional array of string 我愿意将其转换为某种集合类型 以便我可以根据自己的意愿添加 删除和插入元素 在数组中 我无法删除特定位置的元素 我需要这样的集合 我可以在其中删除特定位置的数据 也
  • Android - 9 补丁

    我正在尝试使用 9 块图片创建一个新的微调器背景 我尝试了很多方法来获得完美的图像 但都失败了 s Here is my 9 patch 当我用Draw 9 patch模拟时 内容看起来不错 但是带有箭头的部分没有显示 或者当它显示时 这部

随机推荐

  • Maven 项目集成Test 框架打包提示:Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4

    Maven 打包错误信息 ERROR Failed to execute goal org apache maven plugins maven surefire plugin 2 12 test default test on proje
  • 突破前端反调试--阻止页面不断debugger

    原文地址 https segmentfault com a 11 其实我也不太确定是不是反调试 但是他阻止我看他代码了 那就是反调试 姑且这么称呼吧 问题复现 一次扒某网站的前端代码 打开控制台要看Network 结果发现他们页面一打开控制
  • 最详细的解决:UnboundLocalError: local variable ‘a‘ referenced before assignment

    代码及报错如下 解决 很多人都非常困惑 为什么在test3中可以直接输出a 但是在test3中 使用a 1的时候 就直接报错呢 首先 我们需要明确一个概念 就是全局变量与局部变量 如下图 大家觉得打印的a会是1还是3 答案是1 因为定义在t
  • C语言/C++常见习题问答集锦(四十五) 之数字之谜

    C语言 C 常见习题问答集锦 四十五 之数字之谜 程序之美 1 最大公约数 题目描述 给定N个正整数 求他们的最大公约数 本题要求函数实现 接口如下 int gcd array int num int size 求大小为size的数组num
  • 基于Stomp协议的时间通知机制

    问题导入 系统运行过程中出现了由主持人的操作推动会议流程的场景 如何将主持人的命令通过服务器同步到每个人的设备上 问题分析 在当前的系统设计中使用了C S架构 基本上所有的请求都是终端通过http协议向服务器提出的 而服务器没有办法向终端主
  • pygame飞机大战小游戏(python大作业)

    一 项目背景 python大作业 在查看了老师给的链接发现教学视频不完整 所以借用了同学的 Python编程 从入门到实践 中的一个项目 学习模仿 二 游戏具体介绍 这是一款由辉辉亲自打造的太空对战小游戏 游戏背景 在广袤无垠的太空里有一群
  • 图的遍历(完整代码)

    代码实现功能 1 利用图的邻接矩阵构造并输出图 2 实现图的深度优先搜索遍历 3 实现图的广度优先搜索遍历 include
  • 【支持M1】MacDroid for Mac:Mac和Android安卓设备数据互通

    Mac和Android组合始终存在的唯一问题是无法在这些设备之间足够快地传输数据 但是MacDroid for mac填补了这一空白 MacDroid mac版是Macos上一款安卓手机数据传输助手 MacDroid mac下载支持Mac和
  • 码蹄集 ---- 供水管线 kruskal算法

    供水管线 kruskal算法 克鲁斯卡尔算法 最小生成树算法 应用场景 从连通图中找出最小生成树 和实际相结合的有 水管共线 公交车站路线图 城市间修路等 算法主要思想 将连通网中所有的边按照权值大小做升序排序 从权值最小的边开始选择 只要
  • C语言调用libusb访问USB驱动

    目录 一 环境搭建 1 下载库文件 2 解压 3 配置VS工程 3 1 头文件的配置
  • SyntaxError: unexpected EOF while parsing

    SyntaxError unexpected EOF while parsing 这是典型的没有验证函数参数是否有效 原因是eval str 的字符串为空 你可以运行如下代码 观察输出 try print eval except Excep
  • 六句话给出 Synchronized 和 Lock 的区别

    1 Synchronized 内置的 Java 关键字 Lock 是一个 Java 类 2 Synchronized 无法判断获取锁的状态 Lock 可以判断是否获取到了锁 3 Synchronized 会自动释放锁 Lock 必须要手动释
  • Windows下Anaconda3下载安装详细步骤

    第一步 去官网下载Anaconda Individual Editionhttps www anaconda com products individual 第二步 点击Download 在安装之前 要先安装python的版本 这里我先安装
  • C++ 实验8 继承

    编写一个学生和教师数据输入和显示程序 学生数据有编号 姓名 班级和成绩 教师数据有编号 姓名 职称和部门 要求将编号 姓名输入和显示设计成一个类person 并作为学生类student和教师类teacher的基类 类图如下 代码如下 头文件
  • Win10笔记本(机械革命)亮度调节快捷键失效-已解决

    Win10笔记本 机械革命 亮度调节快捷键失效 已解决 1 确定你已经安装了核心显卡驱动 驱动精灵检查一下 2 右击此电脑 管理 系统工具 设备管理器 监视器 单击展开 卸载dpms 卸载Generic Monitor 选中删除相关驱动 3
  • iText包对每页pdf文件加水印

    https ishare iask sina com cn f 31zwqlKmIwM html
  • 用户编写的python程序、无需修改就可以_python的笔记(一)

    Python的基本特点一种动态解释型的编程语言 规范的代码 Python 采用强制缩进的方式使得代码具有极佳的可读性 高级语言特性 封装内存管理等 可移植性 程序如果避免使用依赖于系统的特性 那么无需修改就可以在任何平台上运行 解释性 直接
  • 带你入门TypeScript

    一 为何学习TS 1 TypeScript 在社区的流行度越来越高 它非常适用于一些大型项目 也非常适用于一些基础库 极大地帮助我们提升了开发效率和体验 2 TypeScript 可以编译出纯净 简洁的 JavaScript 代码 并且可以
  • python画玫瑰图_python windrose(风玫瑰图)

    conda install c https conda anaconda org conda forge windrose b 用pip install windrose可以成功 但是安装的路径 python找不到 from windros
  • 多表联查优化

    多表联查优化我总结有以下几点 优化sql语句 索引优化 反范式设计 业务代码优化 使用缓存 优化sql语句 sql性能分析 查看执行频次 查看执行频次 select insert delete update shwo global sess