zoukankan      html  css  js  c++  java
  • sql优化把派生表改成子查询,查询速度将变快

    使用数据库:MYSQL 5.7.27

    参考资料:

    数据库~Mysql派生表注意的几点~关于百万数据的慢查询问题
    https://blog.csdn.net/weixin_34146410/article/details/93984487
     
    子查询:在一个查询中嵌套另一个查询,则另一个查询成为子查询,也叫内部查询
    派生表:在FROM子句中使用子查询时,从子查询返回的结果集将用作临时表。 该表称为派生表
     
    当查询的复杂sql数据量大时,把 派生表 改成 子查询, 查询速度将变快
    因为派生表不能走索引,子查询可以走索引
     
     两张表:
    ding_talk_employee 钉钉员工表: 总共408条数据
    ding_talk_employee_analysis 钉钉员工统计年份分析表: 总共2259条数据
    在数据量比较小时: 派生表查询速度比子查询快一倍
    派生表sql:
    SELECT
                t0.department_name,
                t0.department_id,
                -- 上一年度正式人员
                IFNULL(t1.beforeYearNormalCount,0) as beforeYearNormalCount,
                -- 当前正式人员
                IFNULL(t2.normalCount,0) as normalCount,
                -- 较上年新增正式人员数
                IFNULL(t2.normalCount,0)-IFNULL(t1.beforeYearNormalCount,0) as normalCompareBeforeYearCount,
                -- 试用人员
                IFNULL(t3.probationCount,0) as probationCount,
                -- 人员折算总计
                IFNULL(t4.sumCoefficient,0) as sumCoefficient
            from
                (
                    select
                        MIN(a.department_name) as department_name,
                        a.department_id,
                        count(1)
                    from ding_talk_employee a
                    where a.department_name !='' -- and dimission_remarks !='不统计'
                    group by a.department_id ORDER BY department_name
                ) as t0
                    LEFT JOIN
                (
                    -- 上一年度正式人员
                    SELECT
                        a.department_id,
                        count( 1 ) AS beforeYearNormalCount
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                        dtea.count_year = DATE_ADD('2021-01-01 00:00:00', INTERVAL - 1 YEAR )
                      AND dtea.employee_status IN ( '3', '5' )
                    GROUP BY a.department_id
                ) AS t1 on t1.department_id=t0.department_id
                    LEFT JOIN
                (
                    -- 当前正式人员
                    SELECT
                        a.department_id,
                        count( 1 ) AS normalCount
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                        dtea.count_year = '2021-01-01 00:00:00'
                      AND dtea.employee_status IN ( '3', '5' )
                    GROUP BY a.department_id
                ) AS t2 on t2.department_id=t0.department_id
                    LEFT JOIN
                (
                    -- 试用人员
                    SELECT
                        a.department_id,
                        count(1) AS probationCount
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                        dtea.count_year = '2021-01-01 00:00:00'
                      AND dtea.employee_status = '2'
                    GROUP BY a.department_name
                ) AS t3 on t3.department_id=t0.department_id
                    LEFT JOIN
                (
                    SELECT
                        a.department_id,
                        SUM(dtea.coefficient) AS sumCoefficient
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                        dtea.count_year = '2021-01-01 00:00:00'
                    GROUP BY a.department_id
                ) AS t4 on t4.department_id=t0.department_id

    不使用缓存的查询时间

    派生表查询时间 0.047s

    使用 explain 命令查看索引使用情况

    总共5个派生表,看索引情况,派生表会自动创建索引

     查看具体耗时步骤:

    使用命令:

    show profiles (查询刚才执行sql的对应id)
    show profile for query 26

    派生表转换成子查询后的sql:

    SELECT
        tu.department_name,
        tu.department_id,
        -- 上一年度正式人员
        tu.beforeYearNormalCount,
        -- 当前正式人员
        tu.normalCount,
        -- 较上年新增正式人员数
        IFNULL(tu.normalCount,0)-IFNULL(tu.beforeYearNormalCount,0) as normalCompareBeforeYearCount,
        -- 试用人员
        tu.probationCount,
        -- 人员折算总计
        tu.sumCoefficient
    FROM (
        SELECT
                MIN(t0.department_name) as department_name,
                t0.department_id,
                
                
                IFNULL(
                (
                    -- 上一年度正式人员
                    SELECT
                        count( 1 ) AS beforeYearNormalCount
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                        a.department_id=t0.department_id
                        AND dtea.count_year = DATE_ADD('2021-01-01 00:00:00', INTERVAL - 1 YEAR )
                      AND dtea.employee_status IN ( '3', '5' )
                    GROUP BY a.department_id
                )
                ,0) as beforeYearNormalCount,
                
                IFNULL(
                (
                    -- 当前正式人员
                    SELECT
                        count( 1 ) AS normalCount
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                        a.department_id=t0.department_id
                        AND    dtea.count_year = '2021-01-01 00:00:00'
                      AND dtea.employee_status IN ( '3', '5' )
                    GROUP BY a.department_id
                )
                ,0) as normalCount,
                
                
                IFNULL(
                (
                    -- 试用人员
                    SELECT
                        count(1) AS probationCount
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                      a.department_id=t0.department_id
                        AND dtea.count_year = '2021-01-01 00:00:00'
                      AND dtea.employee_status = '2'
                    GROUP BY a.department_name
                )
                ,0) as probationCount,
                
                IFNULL(
                (
                    SELECT
                        SUM(dtea.coefficient) AS sumCoefficient
                    FROM
                        ding_talk_employee a
                            INNER JOIN ding_talk_employee_analysis dtea ON a.userid = dtea.userid
                    WHERE
                      a.department_id=t0.department_id
                        AND dtea.count_year = '2021-01-01 00:00:00'
                    GROUP BY a.department_id
                )
                ,0) as sumCoefficient
                
            FROM
                ding_talk_employee t0
            WHERE 
                t0.department_name !='' -- and dimission_remarks !='不统计'
            GROUP BY t0.department_id 
            ORDER BY t0.department_name
    ) as tu

     

     使用子查询的查询时间0.068s

     
     
    作者:海绵般汲取
    出处:https://www.cnblogs.com/gne-hwz/
    版权:本文版权归作者和博客园共有
    转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
  • 相关阅读:
    进程控制
    进程的状态与转换
    进程的概念和特征
    操作系统的体系结构:大内核和微内核
    系统调用
    中断和异常
    【转】Java-----jar反编译修改重新打包
    [转] Android Volley完全解析(一),初识Volley的基本用法
    [转] This Android SDK requires Android Developer Toolkit version 23.0.0 or above
    Can't bind to local 8700 for debugger报错和解决
  • 原文地址:https://www.cnblogs.com/gne-hwz/p/15566510.html
Copyright © 2011-2022 走看看