同事写的一个接口。就是查询评论这一块的,同时查询 6 张表吧。用阿里云服务器 4 核 8G 的,CPU 满载,并发只有 12。对,没错只有 12.然后我发现 mysqld 这个进程使用 cpu85%, 剩下的 15%才给了 JVM。 应该怎么去优化这个接口,12 并发是不给活啊
SQL贴上来吧,总共有
SELECT A.*,B.headIcon from `comt_like`AS A
left join (select userCode,headIcon FROM user_info) as B
on A.userCode = B.userCode
where commentCode in (
select commentCode FROM `comt_parent` where disType = #{disType}
)
ORDER BY commentCode,operationTime
select * FROM `comt_parent_image` where commentCode in (
select commentCode FROM `comt_parent` where disType = #{disType}
)
select * from
(select DISTINCT A.*,C.nickName,C.headIcon,IFNULL(b.num,0) as childReplyCount from `comt_child` as A
left join (select parentCode,count(1) as num from `comt_child` where parentCode is not null
group by parentCode) as B
on A.childCode = B.parentCode
left join (select userCode,headIcon,nickName FROM user_info) as C
on A.userCode = C.userCode
where commentCode in (
select commentCode FROM `comt_parent` where disType = #{disType})
ORDER BY commentCode,childReplyCount DESC,createTime DESC) T
GROUP BY T.commentCode
select A.*,D.nickName,D.headIcon,E.themeName,
ifnull(B.childCount,0) as childCount,ifnull(C.likeCount,0) as likeCount,
childCount+likeCount as sumCount,
(select userCode from `comt_like` where userCode = #{loginUserCode} and commentCode = A.commentCode) as isLike
from comt_parent as A
left join
(select commentCode,count(commentCode) as childCount,parentCode from comt_child
group by commentCode) AS B on A.commentCode = B.commentCode
left join
(select commentCode,count(commentCode) as likeCount from comt_like
group by commentCode) AS C on A.commentCode = C.commentCode
left join
(select nickName,userCode,headIcon from user_info)
as D on A.userCode = D.userCode
left join
(select id,themeName from comt_theme)
as E on A.themeId = E.id
where A.disType = #{disType} and A.commentType = 2
order by sumCount DESC
一共这几条,谢谢
表的结构在这儿
mysql> desc comt_like;
+-------------
| Field
+---------------+-----------
| id | bigint(20)
| commentCode | varchar(255)
| userCode | varchar(255) |
| operationTime | datetime
mysql> desc comt_parent;
+--------------------+-------------
| Field | Type
+--------------------+------------
| id | bigint(20)
| commentCode | varchar(255)
| userCode | varchar(255)
| createTime | datetime
| text | longtext
| disType | int(11)
| indexCode | varchar(255)
| themeId | varchar(255)
| detailedName | varchar(255)
| productDescription | varchar(255)
| isPrize | int(11) unsigned
| commentType | int(11)
mysql> desc comt_parent_image;
+-------------+--------
| Field | Type
+-------------+-----------
| id | bigint(20)
| imageCode | varchar(255)
| commentCode | varchar(255)
| imageUrl | varchar(255) |
| imageIndex | varchar(255) |
mysql> desc comt_child;
+----------------+-----------
| Field | Type
+----------------+--------------
| id | bigint(20) |
| childCode | varchar(255) |
| parentCode | varchar(255) |
| commentCode | varchar(255) |
| userCode | varchar(255) |
| text | varchar(999) |
| createTime | datetime
| parentIsDelete | int(11) |
| childIsDelete | int(11) |
| parentIsRead | int(11) |
| childIsRead | int(11) |
1
JavaFirstMaster 2018-10-31 10:12:20 +08:00
mysql 占用那么高,那就是 mysql 语句需要优化了呀.需要同时查 6 张表是否考虑一下数据结构或者业务逻辑是否合理
|
2
337136897 OP @JavaFirstMaster 大佬 数据结构从哪方面去分析?给个联系方式请教下行否
|
3
leriou 2018-10-31 10:15:12 +08:00
如果是真的查询量特别多, 就把数据预处理到 nosql , 从 nosql 查
|
4
krisbai 2018-10-31 10:17:11 +08:00
把慢查询日志打开看看
|
5
zidian9 2018-10-31 10:17:34 +08:00
查询尽可能不要连表查,可以先查一张表,再通过键 in 的方法查别的表,在程序里写逻辑组装数据。
另外做好 db 索引。 |
6
glacer 2018-10-31 10:18:13 +08:00
1. SQL 语句优化
2. 加缓存 |
7
jbiao520 2018-10-31 10:18:46 +08:00
mysql cpu 高的话那估计是慢查询了,找找 sql 问题,是不是没建索引啊
|
10
lhx2008 2018-10-31 10:28:18 +08:00 via Android
第一次查询把数据加到 redis 里面缓存,有新评论进来再把缓存删掉,这样几百个查询并发都没问题
|
11
sun1991 2018-10-31 10:41:44 +08:00
@zidian9 查询尽可能不要连表查,可以先查一张表,再通过键 in 的方法查别的表
--- 经常看到这种讲法, 自己做表连接的效率比 MYSQL 要高? 是不是说 MYSQL 这块儿的优化做得特别差? |
13
zhaishunqi 2018-10-31 10:51:22 +08:00
先试试 sql 优化吧...
先通过条件过滤数据量大的表,作为一张虚拟表,然后再用数据量不大的表和过滤出来的结果进行联查试试吧. 当然关键的检索字段加索引,但是也不要太多索引. 实在不行,考虑下重新设计这部分的功能吧. |
15
teddy2725 2018-10-31 10:56:16 +08:00
买个 rds, 优化下 sql,cpu 占用这么高估计是 join 多了,索引设计不合理
|
16
wysnylc 2018-10-31 11:17:13 +08:00
拆分多表 sql 为单表,使用 parallelStream 或者 CompleTableFuture 推荐)进行并行执行
去 join 和并行执行才能从代码上提高效率,其他的都是硬件提高导致性能提高而已 |
17
leriou 2018-10-31 11:20:12 +08:00 1
@337136897 现代业务方向是将业务放要使用的数据提前准备好, 准备方式是离线计算+实时计算, 尤其是多表查询用到的数据, 后台实时计算出来存储到 nosql 层, 前台业务的读请求只走 nosql, mysql 这种只对核心的关键业务开发, 大部分业务触及不到 mysql, 需要使用的数据预先处理到缓存层
|
18
neoblackcap 2018-10-31 11:30:33 +08:00
|
19
e9e499d78f 2018-10-31 11:31:18 +08:00 via iPhone 2
开个 ssh 让那个谁上去看看
|
20
micean 2018-10-31 11:35:44 +08:00
没有表结构、没有数据量、也没有 sql ……
你们也能给这么多意见…… |
22
xmh51 2018-10-31 11:39:51 +08:00
数据量不大的情况下 索引作用不是很大,考虑 sql 有问题,你们看下 sql 的问题在哪吧。
|
23
limuyan44 2018-10-31 11:40:07 +08:00 via Android
现在真是什么都劝人上缓存,要不要再劝一下上分布式啊,建议 lz 把 sql 放上来,表结构也可以放上来研究研究。
|
24
xmh51 2018-10-31 11:42:32 +08:00
mysql 可以监控出慢 sql 和查询的 sql。不会的话,手动排查
排查思路:打出接口过程中执行的所有 sql,注意别漏了。 先看下执行 sql 的条数,没问题的话 再一条一条 sql 拿出来使用 navcat 手动执行。看下问题点在哪。 |
25
limuyan44 2018-10-31 11:42:42 +08:00 via Android
还有数据量执行计划这些都可以放上来,不然只能瞎猜。
|
26
Raymon111111 2018-10-31 11:48:58 +08:00
没有场景怎么优化
先看看 sql 和数据量吧 |
28
no1xsyzy 2018-10-31 12:23:46 +08:00
explain <查询语句>
|
29
no1xsyzy 2018-10-31 12:29:12 +08:00
@zidian9 这两个其实做了同样的运算,除非你用了 SELECT * 并连了不该连的表。
顺便,注意删除所有 SELECT *,要啥写啥,不要 SELECT 多个列后再丢弃(同时,抛弃没有对此优化的 ORM )。 |
30
jimrok 2018-10-31 12:52:10 +08:00
初步的想法是你上 memcached,查询一个评论,然后放入 memcachd 里,如果有新评论,过期这个 cache。或者你就将数据库做一个 slave,阿里云有读写分离的地址,你查询走读写分离地址,这样查询请求会被打到 slave 服务器。slave 服务器按照流量收费。另外要把 slave 的配置提高一些,防止复制延迟。
|
31
misaka19000 2018-10-31 12:56:06 +08:00 via Android 1
为什么都在推荐上缓存?第一步不应该是优化 SQL 找到 MySQLCPU 占用率高的原因吗
|
32
bobuick 2018-10-31 13:13:45 +08:00
sql 肯定是需要优化了。
优化到没办法了,就用拆分大法了。一些聚合,排序,联表过滤到逻辑可以放到程序里来做 |
33
Hancock 2018-10-31 13:18:42 +08:00
优化索引,数据库读写分离
|
35
opengps 2018-10-31 13:19:07 +08:00
别只看 cpu,数据库这种应用,你硬盘是 ssd 吗?大部分是因为硬盘的读写,让系统去等待了。
还有个地方要注意,cpu100%并不意味着能正常干活,而是总资源已经不够分的了 |
36
kran 2018-10-31 13:23:13 +08:00 via iPhone
显然首先是优化表结构
|
38
337136897 OP |
39
cgpiao 2018-10-31 14:38:55 +08:00
这么一说我很担心 我写的 php 接口,laravel 写的,连接了 7,8 个表,还有子查询什么的。
|
40
Le4fun 2018-10-31 15:03:24 +08:00
你这 sql 一大坨 瞬间不想看了
|
41
neoblackcap 2018-10-31 15:03:43 +08:00
@337136897 你的表都是没有索引的吗?你都贴了这么多了,何不将慢查询日志跟 explain 语句得到的查询计划一起发上来
|
42
337136897 OP @neoblackcap 数据量不多吧。所以没建索引。慢查询没开,晚点儿我去开一下。explain 语句是在哪里看? - -
|
43
jjwjiang 2018-10-31 15:39:50 +08:00 1
这么多回复就 @neoblackcap 一条靠谱的
你倒是先确定是不是查询的问题呀……执行计划……查询日志 再不济你把语句一个 block 一个 block 慢慢删减,看看哪部分有最大的改善,别一上来就猜原因呀 |
44
realpg 2018-10-31 15:42:15 +08:00
一点数据库基础没有的还不会准备资料的从 0 开始提问学习 DB 优化
|
45
weizhen199 2018-10-31 15:43:06 +08:00
sql 优化,从 xjb 加索引开始
|
46
neoblackcap 2018-10-31 15:46:10 +08:00
@337136897 数据量不多是多少啊,你前面说同事建了索引,这里又全部隐藏了。你们性能调优都是靠散弹枪编程啊?还是撞大运编程?
explain 是 sql 语句啊,你 explain 一下你的 sql 语句就知道了,上面有人说了。再不行你先读 mysql 文档。 软件工程软件工程,不要都是靠猜啊。大胆猜想,实证分析,小心验证! |
47
micean 2018-10-31 16:12:26 +08:00
粗看了下 sql
很多的 in 都可以优化成关联查询 group by 算数量的可以优化成缓存流程 DISTINCT 这个看你的数据量了 评论表为什么要拆成 2 张表 |
48
akira 2018-10-31 18:30:45 +08:00
表结构的索引 补一下,然后每个语句的 explain 补一下
|
49
akira 2018-10-31 18:34:09 +08:00
SELECT A.*,B.headIcon from `comt_like`AS A
left join (select userCode,headIcon FROM user_info) as B // 这个优化反效果了,每次都会对 user_info 表取一次全表,放外层会更好 on A.userCode = B.userCode where commentCode in ( select commentCode FROM `comt_parent` where disType = #{disType} ) ORDER BY commentCode,operationTime |
50
littlewing 2018-10-31 19:14:54 +08:00
1. mysql 的 join 就是残废的,性能特别差,不要用
2. 不要用子查询 |
51
veightz 2018-11-01 02:51:30 +08:00
Java 一般都会 DAO 上再套 Manager 做缓存,不直接关联
评论这种走量的数据后续肯定会做分表,不用 join 趁早出坑 |
52
kios 2018-11-01 08:08:41 +08:00
数据库这块需要优化
|
53
v2orz 2018-11-01 09:47:41 +08:00
|
54
xhinliang 2018-11-01 10:56:18 +08:00
其实大型 Web 后端应用里,很少有连表查询的需求了。
甚至,索引都很少用,一般主键就够了。 |