mysql查询性能优化(数据量非常小,但查询很慢,初步确认是因为使用了左外连接)

时间:2022-01-29 00:47:42

首先,是这么一段sql:

SQL 1:

SELECT
d.id,
d.project_code,
d.push_type,
d.push_name,
d.push_to,
d.push_from,
d.push_way,
tr.isread,
d.push_content,
d.push_attachment,
d.add_time,
d.push_status,
d.push_reviewer,
push_time,
d.reviewer_time,
d.push_class,
d.rel_object,
p.short_name AS project_name,
u1. NAME AS push_to_name,
u2. NAME AS push_from_name,
u3. NAME AS push_reviewer_name
FROM tb_push_data d
    LEFT JOIN tb_project p ON p.short_code = d.project_code
    LEFT JOIN tb_user u1 ON u1. CODE = d.push_to
    LEFT JOIN tb_user u2 ON u2. CODE = d.push_from
    LEFT JOIN tb_user u3 ON u3. CODE = d.push_reviewer
    LEFT JOIN tb_push_log tr ON tr.pushdata_id = d.id
WHERE 1 = 1
    AND d.add_time BETWEEN '2017-01-01' and '2018-01-11'
GROUP BY d.id
LIMIT 0,100

受影响的行: 0
时间: 24.933s



可以看到,仅仅是100条数据,查询时间竟然高达24秒,于是我尝试将左外连接改为交叉连接:

SQL 2:

SELECT
d.id,
d.project_code,
d.push_type,
d.push_name,
d.push_to,
d.push_from,
d.push_way,
tr.isread,
d.push_content,
d.push_attachment,
d.add_time,
d.push_status,
d.push_reviewer,
push_time,
d.reviewer_time,
d.push_class,
d.rel_object,
p.short_name AS project_name,
u1. NAME AS push_to_name,
u2. NAME AS push_from_name,
u3. NAME AS push_reviewer_name
FROM 
tb_push_data d,
tb_project p,
tb_user u1,
tb_user u2,
tb_user u3,
tb_push_log tr
WHERE 1 = 1
and p.short_code = d.project_code
and u1. CODE = d.push_to
and u2. CODE = d.push_from
and u3. CODE = d.push_reviewer
and tr.pushdata_id = d.id
AND d.add_time BETWEEN '2017-01-01' and '2018-01-11'
GROUP BY d.id
LIMIT 0,100

受影响的行: 0
时间: 0.189s



这一下查询时间终于算是正常了,看来很多人说的数据库查询不用外键不用join还是有道理的。
但是这又出现了一个问题, 因为SQL 2没有使用外连接,比如我某条数据是没有推送人的,那这条记录都显示不出来了。

那么,针对目前的这种情况,该如何优化?

9 个解决方案

#1


LIMIT 0,100
----------------- 这个限制了只返回100条,并不是满足条件的只有100条,所以不能说数据量小
至于 LEFT JOIN 和你的交叉连接,两者意义不一样,查询计划不一样,满足条件的数据量也不一样,所以没有可比性(你自己都说,需要的数据出不来了,所以明显是少了,少了数据,速度变更快不正常么?)

这种优化的问题,给出执行计划( EXPLAIN SELECT ....)

#2


初步估计没有索引,试试加个索引
ALTER TABLE tb_push_data ADD KEY(add_time, id)

#3


引用 1 楼 zjcxc 的回复:
LIMIT 0,100
----------------- 这个限制了只返回100条,并不是满足条件的只有100条,所以不能说数据量小
至于 LEFT JOIN 和你的交叉连接,两者意义不一样,查询计划不一样,满足条件的数据量也不一样,所以没有可比性(你自己都说,需要的数据出不来了,所以明显是少了,少了数据,速度变更快不正常么?)
这种优化的问题,给出执行计划( EXPLAIN SELECT ....)


谢谢回复,但是数据量确实不大,在where条件的时间段内的数据一共才1453条。

而且还有一点疑问,您说的:“ 这个限制了只返回100条,并不是满足条件的只有100条,所以不能说数据量小”
如果使用limit显示返回条数也不能时候数据量小,那为什么还要做后端分页呢?反正即使加了偏移量数据量也不算小,还不如全部数据一起返回,再前端执行分页呢

这种优化的问题,给出执行计划( EXPLAIN SELECT ....)

#4


引用 2 楼 zjcxc 的回复:
初步估计没有索引,试试加个索引
ALTER TABLE tb_push_data ADD KEY(add_time, id)


尝试加了索引,时间: 25.323s,并没有快多少,反而还慢了

#5


执行计划呢?

#6


至少我不认为后端分页对 DB 有什么好处(大多数情况下)

#7


引用 5 楼 zjcxc 的回复:
执行计划呢?


不好意思,刚刚忘发了

mysql查询性能优化(数据量非常小,但查询很慢,初步确认是因为使用了左外连接)

#8


LEFT JOIN tb_push_log tr ON tr.pushdata_id = d.id
--------------- 这个没走索引,而且看起来数据量不少,这个上面加索引试试
alter table tb_push_log add key(pushdata_id)

#9


引用 8 楼 zjcxc 的回复:
LEFT JOIN tb_push_log tr ON tr.pushdata_id = d.id
--------------- 这个没走索引,而且看起来数据量不少,这个上面加索引试试
alter table tb_push_log add key(pushdata_id)


成了,非常感谢大神耐心解答,mua

#1


LIMIT 0,100
----------------- 这个限制了只返回100条,并不是满足条件的只有100条,所以不能说数据量小
至于 LEFT JOIN 和你的交叉连接,两者意义不一样,查询计划不一样,满足条件的数据量也不一样,所以没有可比性(你自己都说,需要的数据出不来了,所以明显是少了,少了数据,速度变更快不正常么?)

这种优化的问题,给出执行计划( EXPLAIN SELECT ....)

#2


初步估计没有索引,试试加个索引
ALTER TABLE tb_push_data ADD KEY(add_time, id)

#3


引用 1 楼 zjcxc 的回复:
LIMIT 0,100
----------------- 这个限制了只返回100条,并不是满足条件的只有100条,所以不能说数据量小
至于 LEFT JOIN 和你的交叉连接,两者意义不一样,查询计划不一样,满足条件的数据量也不一样,所以没有可比性(你自己都说,需要的数据出不来了,所以明显是少了,少了数据,速度变更快不正常么?)
这种优化的问题,给出执行计划( EXPLAIN SELECT ....)


谢谢回复,但是数据量确实不大,在where条件的时间段内的数据一共才1453条。

而且还有一点疑问,您说的:“ 这个限制了只返回100条,并不是满足条件的只有100条,所以不能说数据量小”
如果使用limit显示返回条数也不能时候数据量小,那为什么还要做后端分页呢?反正即使加了偏移量数据量也不算小,还不如全部数据一起返回,再前端执行分页呢

这种优化的问题,给出执行计划( EXPLAIN SELECT ....)

#4


引用 2 楼 zjcxc 的回复:
初步估计没有索引,试试加个索引
ALTER TABLE tb_push_data ADD KEY(add_time, id)


尝试加了索引,时间: 25.323s,并没有快多少,反而还慢了

#5


执行计划呢?

#6


至少我不认为后端分页对 DB 有什么好处(大多数情况下)

#7


引用 5 楼 zjcxc 的回复:
执行计划呢?


不好意思,刚刚忘发了

mysql查询性能优化(数据量非常小,但查询很慢,初步确认是因为使用了左外连接)

#8


LEFT JOIN tb_push_log tr ON tr.pushdata_id = d.id
--------------- 这个没走索引,而且看起来数据量不少,这个上面加索引试试
alter table tb_push_log add key(pushdata_id)

#9


引用 8 楼 zjcxc 的回复:
LEFT JOIN tb_push_log tr ON tr.pushdata_id = d.id
--------------- 这个没走索引,而且看起来数据量不少,这个上面加索引试试
alter table tb_push_log add key(pushdata_id)


成了,非常感谢大神耐心解答,mua