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表 didB表 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 联表查询 巨慢的主要内容,如果未能解决你的问题,请参考以下文章