开发记录

Sql 优化 后如何确保结果一致啊

2019-04-12  本文已影响0人  叮咣铛

同事群里发慢sql优化记录

手痒打开一个看看,尝试下

速度提起来了

那么问题来了,你怎么保证优化过的sql结果和之前是一致的?

Sql 优化 后如何确保结果一致啊

即:你没改变他的逻辑

google告诉我 用minus ,对不起Mysql不支持

中间也想过自己搞个Java 多线程 加limit关键字 ,切段比较?感觉太笨拙了,
手里有锤子满世界都是钉子也不行啊

 So
Mysql minus  替代品:

left join  .... is null

先看两个表结构


t1.png t2.png

同样的表结构,
内容 前三条一致,最后一条不同

目标: 找出不同记录数

方式:

select s1.region_id ,s1.name, s2.region_id, s2.name 

from sales_region s1

left join sales_region_new s2 

on s1.region_id = s2.region_id
t3.png

oye!

如果愉快的加个 s2.region_id is null 判断:

select s1.region_id ,s1.name, s2.region_id, s2.name 
from sales_region s1

left join sales_region_new s2 

on s1.region_id = s2.region_id

where s2.region_id is null

类似 minus的效果


t4.png

再直观一点:告诉我 s1 中有 而s2没有的 记录条数

SELECT
COUNT(*) AS s1Have_s2None_counts
FROM
sales_region s1
LEFT JOIN
sales_region_new s2 ON s1.region_id = s2.region_id
WHERE
s2.region_id IS NULL


t5.png

好了,铺垫完毕

回到咱们面对的问题:

如何保证两条sql 返回的结果是一致的?

即 ,当你优化系统中的慢sql时候,
如何验证你修改后的sql和修改前的sql ,结果一致

即使你优化了速度,但不能把逻辑搞错了

例如:

SELECT 
    *
FROM
    c_alarm_data_t
WHERE
    create_date > '2019-03-13'
        AND sensor_no != 'E11'
        AND terminal_no IN (SELECT 
            terminal_no
        FROM
            v_terminal_t
        WHERE
            organization_no IN (SELECT DISTINCT
                    organization_no
                FROM
                    v_terminal_t
                WHERE
                    terminal_no IN (SELECT 
                            terminal_no
                        FROM
                            f_dt_limitsgp_limits
                        WHERE
                            dt_limitsgp_id IN (SELECT 
                                    dt_limitsgp_id
                                FROM
                                    f_dt_user_datalimitsgp
                                WHERE
                                    userid = 'userid99998888test'))));
image8.png

结果有260w, 耗时 8.2s , 这里只展示了100条

优化后(去掉莫名其妙的自己in 自己):

    *
FROM
    c_alarm_data_t
WHERE
    create_date > '2019-03-13'
        AND sensor_no != 'E11'
        AND terminal_no IN 
        
        -- (SELECT 
--             terminal_no
--         FROM
--             v_terminal_t
--         WHERE
--             organization_no IN (SELECT DISTINCT
--                     organization_no
--                 FROM
--                     v_terminal_t
--                 WHERE
--                     terminal_no IN 
--                     
                    (SELECT 
                            terminal_no
                        FROM
                            f_dt_limitsgp_limits
                        WHERE
                            dt_limitsgp_id IN (SELECT 
                                    dt_limitsgp_id
                                FROM
                                    f_dt_user_datalimitsgp
                                WHERE
                                    userid = 'userid99998888test'));
image019.png

用时0.019s

速度提升431倍!!!

Sql 优化 后如何确保结果一致啊

sql 区别如下:


imageDiff.png

验证两个sql结果一致:

SELECT 
    COUNT(t1.alarm_id)
FROM
    (SELECT 
        *
    FROM
        c_alarm_data_t
    WHERE
        create_date BETWEEN '2019-04-02 12:00:00' AND '2019-04-02 12:00:01'
            AND sensor_no != 'E11'
            AND terminal_no IN (SELECT 
                terminal_no
            FROM
                f_dt_limitsgp_limits
            WHERE
                dt_limitsgp_id IN (SELECT 
                        dt_limitsgp_id
                    FROM
                        f_dt_user_datalimitsgp
                    WHERE
                        userid = 'userid99998888test'))
    LIMIT 5) AS t1
        LEFT JOIN
    (SELECT 
        *
    FROM
        c_alarm_data_t
    WHERE
        create_date BETWEEN '2019-04-02 12:00:00' AND '2019-04-02 12:00:01'
            AND sensor_no != 'E11'
            AND terminal_no IN (SELECT 
                terminal_no
            FROM
                v_terminal_t
            WHERE
                organization_no IN (SELECT DISTINCT
                        organization_no
                    FROM
                        v_terminal_t
                    WHERE
                        terminal_no IN (SELECT 
                                terminal_no
                            FROM
                                f_dt_limitsgp_limits
                            WHERE
                                dt_limitsgp_id IN (SELECT 
                                        dt_limitsgp_id
                                    FROM
                                        f_dt_user_datalimitsgp
                                    WHERE
                                        userid = 'userid99998888test'))))
    LIMIT 5) AS t2 ON t1.alarm_id = t2.alarm_id
WHERE
    t2.alarm_id IS NULL;
imageCnt0.png

为了提高速度,sql做了轻微修改,
时间段缩小为1s
limit 5 只取5条
即使这样,这个判定还要8.1s...

做个记录吧,谁有更好的方案,欢迎指教

话说 简书为何没有标签功能?

上一篇 下一篇

猜你喜欢

热点阅读