mysql 联表查询 巨慢

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql 联表查询 巨慢相关的知识,希望对你有一定的参考价值。

select A.Gne,B.dvalue FROM doc_iseq _rele AS B INNER JOIN doc_iseq AS A ON A.did = B.did where B.uid = 1;

能优化吗doc_iseq _rele 这个表有1000W的数据

问题

我们有一个 SQL,用于找到没有主键 / 唯一键的表,但是在 mysql 5.7 上运行特别慢,怎么办?

实验

我们搭建一个 MySQL 5.7 的环境,此处省略搭建步骤。

写个简单的脚本,制造一批带主键和不带主键的表:

执行一下脚本:

现在执行以下 SQL 看看效果:

...


执行了 16.80s,感觉是非常慢了。

现在用一下 DBA 三板斧,看看执行计划:


感觉有点惨,由于 information_schema.columns 是元数据表,没有必要的统计信息。

那我们来 show warnings 看看 MySQL 改写后的 SQL:

我们格式化一下 SQL:


可以看到 MySQL 将

select from A where A.x not in (select x from B) //非关联子查询

转换成了

select from A where not exists (select 1 from B where B.x = a.x) //关联子查询

如果我们自己是 MySQL,在执行非关联子查询时,可以使用很简单的策略:

select from A where A.x not in (select x from B where ...) //非关联子查询:1. 扫描 B 表中的所有记录,找到满足条件的记录,存放在临时表 C 中,建好索引2. 扫描 A 表中的记录,与临时表 C 中的记录进行比对,直接在索引里比对,

而关联子查询就需要循环迭代:

select from A where not exists (select 1 from B where B.x = a.x and ...) //关联子查询扫描 A 表的每一条记录 rA:     扫描 B 表,找到其中的第一条满足 rA 条件的记录。

显然,关联子查询的扫描成本会高于非关联子查询。

我们希望 MySQL 能先"缓存"子查询的结果(缓存这一步叫物化,MATERIALIZATION),但MySQL 认为不缓存更快,我们就需要给予 MySQL 一定指导。


...

可以看到执行时间变成了 0.67s。

整理

我们诊断的关键点如下:

\\1. 对于 information_schema 中的元数据表,执行计划不能提供有效信息。

\\2. 通过查看 MySQL 改写后的 SQL,我们猜测了优化器发生了误判。

\\3. 我们增加了 hint,指导 MySQL 正确进行优化判断。

但目前我们的实验仅限于猜测,猜中了万事大吉,猜不中就无法做出好的诊断。

参考技术A 给did和uid加上索引追问

已经加上了 还是不行

追答

两个表的表定义发来看看

本回答被提问者采纳
参考技术B A表 did
B表 did ,uid
有没有索引
参考技术C A.Gne,B.dvalue加上索引呢?追问

已经加上了 还是慢

mysql带条件查询,联表查询

---恢复内容开始---

1,用于设定所select出来的数据是否允许出现重复行(完全相同的数据行)

all:允许出现——默认不写就是All(允许的)。

distinct:不允许出现——就是所谓的“消除重复行”

 

2,where:条件

 

3,group by:分组依据 后面加表的字段名,通常只进行一个字段的分组

mysql表查询语法形式:select [all | distinct] 字段名或表达式 from 表名 [where] [group by] [having] [order by] [limit];

练习题:共有下面四张表    学生表:student  教师表:teacher  课程表:course 成绩表:score

 

1,查询Score表中至少有5名学生选修的并以3开头的课程的平均分数

--操作表score,以cno分组并且cno是以3开头,取出各个cno的总数,及与cno对应的degree的平均值

select count(cno),avg(degree) from score where cno like ‘3%‘ group by cno;

 

 

--从虚拟表中找到cno总数大于5的

select * from

(select count(cno) a,avg(degree) b from score where cno like ‘3%‘ group by cno) c

where a>5;

 

2,查询所有学生的Sno、Cname和Degree列

--找到student的sno
 select sno from student;


 --找到score 的sno,degree,cno
 select sno,degree,cno from score;


 --找到course的cno
 select cno,cname from course;


 --组成新表cno sno degree
 select a.cno,b.sno,b.sname,a.degree from (select sno,degree,cno from score) a  join (select sno,sname from student) b on a.sno=b.sno;


 --组成有cname cno sn degree sname的表
 select d.cname,e.cno,e.sno,e.degree,e.sname
 from
   (select a.cno,b.sno,b.sname,a.degree from (select sno,degree,cno from score) a  join (select sno,sname from student) b on a.sno=b.sno) as e 
  join 
  (select cname,cno from course) as d
  on d.cno=e.cno;

 

3,查询“95033”班学生的平均分

--从student取sno class,条件是class是95033的

select sno,class from student where class=‘95033‘;

 

--取出score中sno degree

select sno,degree from score;

 

--将上面两张表组成一张,取degree的平均值

select avg(degree) from

(select sno,class from student where class=‘95033‘) a

join

(select sno,degree from score) b

on a.sno=b.sno;

 

4,查询选修“3-105”课程的成绩高于“109”号同学成绩的所有同学的记录

--将109号的成绩取出

select degree from score where sno=‘109‘ and cno=‘3-105‘;

 

-- 得出最终表

select * from score

where

degree>(select degree from score where sno=‘109‘ and cno=‘3-105‘)

and cno=‘3-105‘;

 

5,查询和学号为108的同学同年出生的所有学生的Sno、Sname和Sbirthday列

--找到student中sno为108 的Sbirthday
select year(sbirthday) from student where sno=‘108‘;


-- 得出最终表
select sno,sname,sbirthday from student

where

year(sbirthday)=(select year(sbirthday) from student where sno=‘108‘);


















以上是关于mysql 联表查询 巨慢的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB 查询技巧(1) - 字段相等

MySQL联表查询

mssql联表查询

mysql联表查询脚本

mysql联表查询

MySQL——联表查询