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...
做个记录吧,谁有更好的方案,欢迎指教
话说 简书为何没有标签功能?