用LEFT JOIN优化JOIN

如何解决用LEFT JOIN优化JOIN

| 我在优化此查询时遇到问题:
SELECT a.id
FROM a
JOIN b ON a.id=b.id
LEFT JOIN c ON a.id=c.id
WHERE
   (b.c1=\'12345\' OR c.c1=\'12345\')
   AND (a.c2=0 OR b.c3=1)
   AND a.c4=\'active\'
GROUP BY a.id;
该查询花费7s,而当仅联接
b
c
中的一个时,查询花费0s。说明:
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: a
         type: ref
possible_keys: PRIMARY(id),c4,c2
          key: c4
      key_len: 1
          ref: const
         rows: 80775
        Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: c
         type: ref
possible_keys: id_c1_unique,id
          key: id_c1
      key_len: 4
          ref: database.a.id
         rows: 1
        Extra: Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: b
         type: ref
possible_keys: id_c1_unique,id,c1,c3
          key: id
      key_len: 4
          ref: database.a.id
         rows: 2
        Extra: Using where
b
中总是有1个匹配行,
c
中最多有1个匹配行。如果MySQL从获取与
c1
文字匹配的
b
c
行开始,然后基于
id
加入
a
,它将以
a
开始,它将更快。 细节: 我的ISAM 所有列都有索引(_unique是UNIQUE) 所有列都不为空 我尝试过的 更改联接的顺序 将WHERE条件移至ON子句 子选择
b.c1
c.c1
(WHERE b.id =(SELECT b.id FROM b WHERE c1 = \'12345 \'))
b
c
的使用索引 我知道我可以使用带有UNION的两个SELECT来做到这一点,但是由于查询的生成方式,我需要尽可能避免这种情况。 编辑:添加创建表 带有相关列的16个字符。
CREATE TABLE `a` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,`c2` tinyint(1) NOT NULL,`c4` enum(\'active\',\'pending\',\'closed\') NOT NULL,PRIMARY KEY (`id`),KEY `c2` (`c2`)
  KEY `c4` (`c4`),) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `b` (
    `b_id` int(11) NOT NULL AUTO_INCREMENT,`id` int(11) NOT NULL DEFAULT \'0\',`c1` int(11) NOT NULL,`c3` tinyint(1) NOT NULL,PRIMARY KEY (`b_id`),UNIQUE KEY `id_c1_unique` (`id`,`c1`),KEY `c1` (`c1`),KEY `c3` (`c3`),) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `c` (
    `c_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`id` int(11) NOT NULL,PRIMARY KEY (`c_id`),KEY `id` (`id`),) ENGINE=MyISAM DEFAULT CHARSET=utf8;
    

解决方法

不是肯定的,但是我很确定更改联接顺序并将条件移动到on子句无关紧要。 我不确定这里是否有足够的信息可以肯定知道,但是我猜\“所有列都有索引\”是您的问题。对于任何特定查询,每个表将仅使用一个索引。因此,如果您在a.id上有一个索引,在a.c2上有一个单独的索引,而在a.c4上有一个第三个索引。好吧,它只会用一个。 索引中似乎有几列。因此,您只需要联接2个表,就可以免费使用“有用的”索引。 我的建议是检查您的索引,并使它们覆盖此查询正在使用的适当字段(如果可能)。 索引ID&C2&C4 b在id&c1&c3上的索引 ID和C1上的C索引     ,
select STRAIGHT_JOIN 
      distinct a.ID
   from
      a
         join b
            on a.ID = b.ID
         left join c
            on a.id = c.id
            and c.c1 = \'12345\'
   where
          a.C4 = \'active\'
      and ( a.c2 = 0 or b.c3 = 1 )
      and ( b.c1 = \'12345\' or c.c1=\'12345\' )
    ,OP在这里回答。 我确定的是,MySQL首先读取效率较低的表的行为是所有LEFT JOIN的固有问题,其中效率较低的表位于左侧。根据MySQL手册中的LEFT JOIN和RIGHT JOIN Optimization:   MySQL实现了“ 19”,如下所示:         表
B
被设置为依赖于表
A
及其相关的所有表    所以:
SELECT a.id
FROM a
LEFT JOIN c ON a.id=c.id
GROUP BY a.id;
即使查询计划显示读取
c
效率更高,也总是会先读取
a
。切换表会使MySQL首先从ѭ2读取:
SELECT a.id
FROM c
LEFT JOIN a ON c.id=a.id
GROUP BY a.id;
就我而言,两个查询都返回相同的结果。显然,我缺少一些概念性的知识,要求进行LEFT JOIN时始终首先读取左侧表。在我看来,可以很容易地首先读取右侧表,而MySQL仍可以生成相同的结果(对于某些查询,不一定是对所有LEFT JOIN而言)。如果可以的话,尽管这种优化可能早就已经添加了,所以我想我只是想念这个概念。 最后,切换表的顺序对我来说不是一个好的解决方案。我最终将
b
c
合并到一个表中,这简化了应用程序,因此应该从头开始。使用单个表,我可以执行JOIN而不是LEFT JOIN,从而完全避免了该问题。 另一个可能的解决方案是创建一个包含两个表的视图,从而为JOIN from提供一个视图。我没有测试。 TL; DR:更改表的顺序以将最有效率的表放在首位(如果结果集相同,而不考虑顺序)。或者将
b
c
合并到一个表中。或者可能创建一个结合了
b
c
的视图。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-