优化MySQL分页的复杂查询

前情背景:

       开发过程中会遇到很多查询MySQL复杂查询语句,涉及到连接表,聚合计算,排序,分组,分页等。分页用的是最多的,这种情况下,MySQL数据库可能会遇到性能瓶颈,导致这样的查询时间长或者超时,最可怕的还有可能导致没法操作MySQL数据库。

       在遇到这样的查询的时候,算是发现问题了。但要怎么解决呢?

     

      分析其原因,查询SQL语句也没有写的冗余,但是很多产品,什么都想要,需求不断的变,导致表的结构有些不合理。优化表有时候可以,不仅麻烦,而且还不一定可行,时间也不够。有没有更好的办法解决呢?

     

    通过打开MySQL的配置文件,一般是/etc/my.conf,查找

    slow_query_log_file = 

    后面的就是慢查询日志文件

    可以看到查询的重要信息(查询时间,行检查条数)。

    也可以用在MySQL中将执行的SQL语句前加上EXPLAIN,查看其详细信息。可以看到查询的重要信息,其中有个type列,此列说明查询的类型,一般慢查询都是All:表示全查询,是最慢的。const是带索引的查询最快。还有其他的类型(ref,eq_ref等)。如果能改成const的或者eq_ref类型的查询,性能就会成十成百倍的提高。如何做到呢?

     laravel5.5框架用有自带的分页,用到group/order by,变成全查询,所以慢。所以使用自定义分页,如下SQL查询:

EXPLAIN SELECT
    `u`.*,
    `us`.`share_img_url`,
    `up`.`promoter_id`,
    ( SELECT SUM( o.money ) FROM pm_orders o WHERE o.user_id = u.id GROUP BY o.user_id ) money_total,
    ( SELECT SUM( usc.promote_people_total ) FROM p_users_statistics usc WHERE usc.user_id = u.id GROUP BY usc.user_id ) people_total,
    ( SELECT nickname FROM p_users u WHERE up.promoter_id = u.id ) promoter_name,
    (
    SELECT
        SUM( awr.award_num ) 
    FROM
        pm_award_records awr 
    WHERE
        awr.award_type = 5 
        AND u.id = awr.praise_invitor_user_id 
    GROUP BY
        awr.praise_invitor_user_id 
    ) get_cash_num,
    `ccc`.`thread_total`,
    ad.nickname AS agent_name 
FROM
    `p_users` `u`
    LEFT JOIN `p_users_shares` `us` ON `us`.`user_id` = `u`.`id`
    LEFT JOIN `p_users_promoter` `up` ON `up`.`user_id` = `u`.`id`
    LEFT JOIN (
    SELECT
        tmp.*,
        count( * ) AS thread_total 
    FROM
        (
        SELECT
            uuu.id,
            pup.promoter_id 
        FROM
            p_users AS uuu
            INNER JOIN p_users_promoter AS pup ON uuu.id = pup.user_id 
        WHERE
            uuu.mobile != '' 
        ) AS tmp
        LEFT JOIN p_users_promoter AS pup1 ON pup1.user_id = tmp.id 
    GROUP BY
        pup1.promoter_id 
    ) AS ccc ON `ccc`.`promoter_id` = `u`.`id`
    LEFT JOIN `pm_admin` `ad` ON `ad`.`id` = `u`.`agent_person_id` 
WHERE
    ( `u`.`is_star` IN ( 0, 1 ) ) 
GROUP BY
    `u`.`id` 
ORDER BY
    thread_total DESC 
    LIMIT 0,
    20;

取出前20条数据,这个数据快,但要做分页的话,需要知道记录的总条数,这样查询的话,非常的慢,要大约30秒钟。

知道是查询总条数慢,由于laravel5.5在group by的时候没法使用索引,所以是全查询。但是要知道总条数,不需要做很多排序和分组操作,去掉这些操作后,在查询的话,就性能大幅的提升。

此方法在复杂的自定义查询中是通用的,简单吧!

转载于:https://my.oschina.net/michaelshu/blog/1935462

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值