V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
337136897
V2EX  ›  程序员

Java 写的一个接口, CPU 满载下只有 12 并发量......,如何改善

  •  
  •   337136897 · 2018-10-31 10:08:59 +08:00 · 5566 次点击
    这是一个创建于 2217 天前的主题,其中的信息可能已经有所发展或是发生改变。

    同事写的一个接口。就是查询评论这一块的,同时查询 6 张表吧。用阿里云服务器 4 核 8G 的,CPU 满载,并发只有 12。对,没错只有 12.然后我发现 mysqld 这个进程使用 cpu85%, 剩下的 15%才给了 JVM。 应该怎么去优化这个接口,12 并发是不给活啊

    第 1 条附言  ·  2018-10-31 14:35:13 +08:00

    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
    
    
    

    一共这几条,谢谢

    第 2 条附言  ·  2018-10-31 14:44:07 +08:00

    表的结构在这儿

    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)      | 
    
    
    
    54 条回复    2018-11-01 10:56:18 +08:00
    JavaFirstMaster
        1
    JavaFirstMaster  
       2018-10-31 10:12:20 +08:00
    mysql 占用那么高,那就是 mysql 语句需要优化了呀.需要同时查 6 张表是否考虑一下数据结构或者业务逻辑是否合理
    337136897
        2
    337136897  
    OP
       2018-10-31 10:13:31 +08:00
    @JavaFirstMaster 大佬 数据结构从哪方面去分析?给个联系方式请教下行否
    leriou
        3
    leriou  
       2018-10-31 10:15:12 +08:00
    如果是真的查询量特别多, 就把数据预处理到 nosql , 从 nosql 查
    krisbai
        4
    krisbai  
       2018-10-31 10:17:11 +08:00
    把慢查询日志打开看看
    zidian9
        5
    zidian9  
       2018-10-31 10:17:34 +08:00
    查询尽可能不要连表查,可以先查一张表,再通过键 in 的方法查别的表,在程序里写逻辑组装数据。
    另外做好 db 索引。
    glacer
        6
    glacer  
       2018-10-31 10:18:13 +08:00
    1. SQL 语句优化
    2. 加缓存
    jbiao520
        7
    jbiao520  
       2018-10-31 10:18:46 +08:00
    mysql cpu 高的话那估计是慢查询了,找找 sql 问题,是不是没建索引啊
    337136897
        8
    337136897  
    OP
       2018-10-31 10:19:36 +08:00
    @jbiao520 数据不多,同事已经建了索引了
    337136897
        9
    337136897  
    OP
       2018-10-31 10:22:00 +08:00
    @leriou 就是 mongo 或者 redis?
    lhx2008
        10
    lhx2008  
       2018-10-31 10:28:18 +08:00 via Android
    第一次查询把数据加到 redis 里面缓存,有新评论进来再把缓存删掉,这样几百个查询并发都没问题
    sun1991
        11
    sun1991  
       2018-10-31 10:41:44 +08:00
    @zidian9 查询尽可能不要连表查,可以先查一张表,再通过键 in 的方法查别的表
    --- 经常看到这种讲法, 自己做表连接的效率比 MYSQL 要高? 是不是说 MYSQL 这块儿的优化做得特别差?
    337136897
        12
    337136897  
    OP
       2018-10-31 10:42:38 +08:00
    @sun1991 那应该咋整
    zhaishunqi
        13
    zhaishunqi  
       2018-10-31 10:51:22 +08:00
    先试试 sql 优化吧...
    先通过条件过滤数据量大的表,作为一张虚拟表,然后再用数据量不大的表和过滤出来的结果进行联查试试吧.
    当然关键的检索字段加索引,但是也不要太多索引.
    实在不行,考虑下重新设计这部分的功能吧.
    eslizn
        14
    eslizn  
       2018-10-31 10:51:31 +08:00
    @sun1991 +1,合理利用好索引,避免笛卡尔积的情况下 连表查比分开多次查效率要高的多
    teddy2725
        15
    teddy2725  
       2018-10-31 10:56:16 +08:00
    买个 rds, 优化下 sql,cpu 占用这么高估计是 join 多了,索引设计不合理
    wysnylc
        16
    wysnylc  
       2018-10-31 11:17:13 +08:00
    拆分多表 sql 为单表,使用 parallelStream 或者 CompleTableFuture 推荐)进行并行执行
    去 join 和并行执行才能从代码上提高效率,其他的都是硬件提高导致性能提高而已
    leriou
        17
    leriou  
       2018-10-31 11:20:12 +08:00   ❤️ 1
    @337136897 现代业务方向是将业务放要使用的数据提前准备好, 准备方式是离线计算+实时计算, 尤其是多表查询用到的数据, 后台实时计算出来存储到 nosql 层, 前台业务的读请求只走 nosql, mysql 这种只对核心的关键业务开发, 大部分业务触及不到 mysql, 需要使用的数据预先处理到缓存层
    neoblackcap
        18
    neoblackcap  
       2018-10-31 11:30:33 +08:00
    @sun1991 +1,不看查询计划,不看索引情况,上来直接禁止 JOIN,分表查询,上 nosql。这大概是 V2EX 数据库调优的政治正确。

    @337136897 我觉得你调优先看慢查询定位问题。如果查询问题都不大,就是机器性能不行就提高 rds 实例性能。
    e9e499d78f
        19
    e9e499d78f  
       2018-10-31 11:31:18 +08:00 via iPhone   ❤️ 2
    开个 ssh 让那个谁上去看看
    micean
        20
    micean  
       2018-10-31 11:35:44 +08:00
    没有表结构、没有数据量、也没有 sql ……
    你们也能给这么多意见……
    337136897
        21
    337136897  
    OP
       2018-10-31 11:36:58 +08:00
    @wysnylc 老哥你说的这个我压根儿没听懂
    xmh51
        22
    xmh51  
       2018-10-31 11:39:51 +08:00
    数据量不大的情况下 索引作用不是很大,考虑 sql 有问题,你们看下 sql 的问题在哪吧。
    limuyan44
        23
    limuyan44  
       2018-10-31 11:40:07 +08:00 via Android
    现在真是什么都劝人上缓存,要不要再劝一下上分布式啊,建议 lz 把 sql 放上来,表结构也可以放上来研究研究。
    xmh51
        24
    xmh51  
       2018-10-31 11:42:32 +08:00
    mysql 可以监控出慢 sql 和查询的 sql。不会的话,手动排查
    排查思路:打出接口过程中执行的所有 sql,注意别漏了。
    先看下执行 sql 的条数,没问题的话 再一条一条 sql 拿出来使用 navcat 手动执行。看下问题点在哪。
    limuyan44
        25
    limuyan44  
       2018-10-31 11:42:42 +08:00 via Android
    还有数据量执行计划这些都可以放上来,不然只能瞎猜。
    Raymon111111
        26
    Raymon111111  
       2018-10-31 11:48:58 +08:00
    没有场景怎么优化

    先看看 sql 和数据量吧
    wysnylc
        27
    wysnylc  
       2018-10-31 12:02:05 +08:00
    @337136897 #21 并行,异步编程,详情百度
    no1xsyzy
        28
    no1xsyzy  
       2018-10-31 12:23:46 +08:00
    explain <查询语句>
    no1xsyzy
        29
    no1xsyzy  
       2018-10-31 12:29:12 +08:00
    @zidian9 这两个其实做了同样的运算,除非你用了 SELECT * 并连了不该连的表。
    顺便,注意删除所有 SELECT *,要啥写啥,不要 SELECT 多个列后再丢弃(同时,抛弃没有对此优化的 ORM )。
    jimrok
        30
    jimrok  
       2018-10-31 12:52:10 +08:00
    初步的想法是你上 memcached,查询一个评论,然后放入 memcachd 里,如果有新评论,过期这个 cache。或者你就将数据库做一个 slave,阿里云有读写分离的地址,你查询走读写分离地址,这样查询请求会被打到 slave 服务器。slave 服务器按照流量收费。另外要把 slave 的配置提高一些,防止复制延迟。
    misaka19000
        31
    misaka19000  
       2018-10-31 12:56:06 +08:00 via Android   ❤️ 1
    为什么都在推荐上缓存?第一步不应该是优化 SQL 找到 MySQLCPU 占用率高的原因吗
    bobuick
        32
    bobuick  
       2018-10-31 13:13:45 +08:00
    sql 肯定是需要优化了。
    优化到没办法了,就用拆分大法了。一些聚合,排序,联表过滤到逻辑可以放到程序里来做
    Hancock
        33
    Hancock  
       2018-10-31 13:18:42 +08:00
    优化索引,数据库读写分离
    qiyuey
        34
    qiyuey  
       2018-10-31 13:19:00 +08:00   ❤️ 1
    @sun1991 我的理解是,第一次的查询,和第二次的 in,都可以走缓存不走 DB,极大的减轻了 DB 的压力
    opengps
        35
    opengps  
       2018-10-31 13:19:07 +08:00
    别只看 cpu,数据库这种应用,你硬盘是 ssd 吗?大部分是因为硬盘的读写,让系统去等待了。
    还有个地方要注意,cpu100%并不意味着能正常干活,而是总资源已经不够分的了
    kran
        36
    kran  
       2018-10-31 13:23:13 +08:00 via iPhone
    显然首先是优化表结构
    ragnaroks
        37
    ragnaroks  
       2018-10-31 13:33:23 +08:00
    @opengps +1
    帮助多家微小企业优化过 DB,基本都是磁盘 IO 不足(阿里云 30M)
    337136897
        38
    337136897  
    OP
       2018-10-31 14:36:45 +08:00
    cgpiao
        39
    cgpiao  
       2018-10-31 14:38:55 +08:00
    这么一说我很担心 我写的 php 接口,laravel 写的,连接了 7,8 个表,还有子查询什么的。
    Le4fun
        40
    Le4fun  
       2018-10-31 15:03:24 +08:00
    你这 sql 一大坨 瞬间不想看了
    neoblackcap
        41
    neoblackcap  
       2018-10-31 15:03:43 +08:00
    @337136897 你的表都是没有索引的吗?你都贴了这么多了,何不将慢查询日志跟 explain 语句得到的查询计划一起发上来
    337136897
        42
    337136897  
    OP
       2018-10-31 15:38:40 +08:00
    @neoblackcap 数据量不多吧。所以没建索引。慢查询没开,晚点儿我去开一下。explain 语句是在哪里看? - -
    jjwjiang
        43
    jjwjiang  
       2018-10-31 15:39:50 +08:00   ❤️ 1
    这么多回复就 @neoblackcap 一条靠谱的
    你倒是先确定是不是查询的问题呀……执行计划……查询日志
    再不济你把语句一个 block 一个 block 慢慢删减,看看哪部分有最大的改善,别一上来就猜原因呀
    realpg
        44
    realpg  
       2018-10-31 15:42:15 +08:00
    一点数据库基础没有的还不会准备资料的从 0 开始提问学习 DB 优化
    weizhen199
        45
    weizhen199  
       2018-10-31 15:43:06 +08:00
    sql 优化,从 xjb 加索引开始
    neoblackcap
        46
    neoblackcap  
       2018-10-31 15:46:10 +08:00
    @337136897 数据量不多是多少啊,你前面说同事建了索引,这里又全部隐藏了。你们性能调优都是靠散弹枪编程啊?还是撞大运编程?
    explain 是 sql 语句啊,你 explain 一下你的 sql 语句就知道了,上面有人说了。再不行你先读 mysql 文档。
    软件工程软件工程,不要都是靠猜啊。大胆猜想,实证分析,小心验证!
    micean
        47
    micean  
       2018-10-31 16:12:26 +08:00
    粗看了下 sql
    很多的 in 都可以优化成关联查询
    group by 算数量的可以优化成缓存流程
    DISTINCT 这个看你的数据量了

    评论表为什么要拆成 2 张表
    akira
        48
    akira  
       2018-10-31 18:30:45 +08:00
    表结构的索引 补一下,然后每个语句的 explain 补一下
    akira
        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
    littlewing
        50
    littlewing  
       2018-10-31 19:14:54 +08:00
    1. mysql 的 join 就是残废的,性能特别差,不要用
    2. 不要用子查询
    veightz
        51
    veightz  
       2018-11-01 02:51:30 +08:00
    Java 一般都会 DAO 上再套 Manager 做缓存,不直接关联
    评论这种走量的数据后续肯定会做分表,不用 join 趁早出坑
    kios
        52
    kios  
       2018-11-01 08:08:41 +08:00
    数据库这块需要优化
    v2orz
        53
    v2orz  
       2018-11-01 09:47:41 +08:00
    @sun1991 #11

    现在普遍的说法是,DBMS 重点在存储,计算的工作尽量由应用做,尽管可能绝对效率不如 SQL 计算
    因为应用扩展、拆分、后续维护都更容易
    xhinliang
        54
    xhinliang  
       2018-11-01 10:56:18 +08:00
    其实大型 Web 后端应用里,很少有连表查询的需求了。
    甚至,索引都很少用,一般主键就够了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1213 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 23:21 · PVG 07:21 · LAX 15:21 · JFK 18:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.