SQL优化案例(2):OR条件优化
接下来上⼀篇⽂章《 SQL优化案例(1):隐式转换》的介绍,此处内容围绕OR的优化展开。
在MySQL中,同样的查询条件,如果变换OR在SQL语句中的位置,那么查询的结果也会有差异,在多个复杂的情况下,可能会带来索引选择不佳的性能隐患,为了避免执⾏效率⼤幅度下降的问题,我们可以适当考虑使⽤统⼀所有对查询逻辑复杂的SQL进⾏分离。
常见OR使⽤场景,请阅读以下案例。
案例⼀:不同列使⽤OR条件查询
1.待优化场景
SELECT
..
..
FROM`t1` a
ken= '16149684'
AND a.store_id= '242950'
istrationId IS NOT NULL
istrationId<> '')
OR a.uid= 308475
istrationId IS NOT NULL
istrationId<> ''
执⾏计划
+--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+
| id          | select_type          | table          | type          | key              | key_len          | ref          | rows          | Extra                                      |
+--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+
| 1            | SIMPLE                | a              | range          |idx_registrationid | 99                |              | 100445        | Using index condition; Using where          |
+--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+
共返回1⾏记录,花费 5 ms 。
2.场景解析
从查询条件中可以研磨令牌和uid过滤性都⾮常好,但是由于使⽤了,或者,需要采⽤索引合并的⽅法才能获得⽐较好的性能。但在实际执⾏过程中MySQL优化器替代选择了使⽤registrationId的索引,导致SQL的性能很差。
3.场景优化
我们将SQL改写成union all的形式。
SELECT
...
...
FROM`t1` a
ken = '16054473'
AND a.store_id = '138343'
AND b.is_refund = 1
AND (a.registrationId IS NOT NULL
istrationId <> '')
union all
SELECT
.
..
...
FROM`t1` a
where a.uid = 181579
istrationId IS NOT NULL
istrationId <> ''
+--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+
| id          | select_type          | table          | type          | possible_keys                | key          | key_len          | ref                          | rows          | Extra                              |
+--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+
| 1            | PRIMARY              | a              | ref            | IDX_TOKEN,IDX_STORE_ID_TOKEN | IDX_TOKEN    | 63                | const                        | 1              | Using index condition; Using where | | 1            | PRIMARY              | b              | eq_ref        | PRIMARY                      | PRIMARY      | 4                | youdian_life_le_id | 1              | Using where                        |
| 2            | UNION                | a              | const          | PRIMARY                      | PRIMARY      | 4                | const                        | 1              |                                    |
| 2            | UNION                | b              | const          | PRIMARY                      | PRIMARY      | 4                | const                        | 0              | unique row not found              |
|              | UNION RESULT          | <union1,2>      | ALL            |                              |              |                  |                              |                | Using temporary                    |
+--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+
共返回5⾏记录,花费 5 ms 。
通过对⽐优化前后的执⾏计划,可以明显修剪,将SQL合并成两个⼦查询,再使⽤union对结果进⾏合
c语言程序设计搜题软件并,稳定性和安全性更好,性能更⾼。
案例⼆:同⼀列使⽤OR查询条件
1.待优化场景
select
....
....
from
t1 as mci
left join t1 as ccv2_1 on ccv2_1.unique_no = mci=category_no1
left join t1 as ccv2_2 on ccv2_2.unique_no = mci=category_no2
left join t1 as ccv2_3 on ccv2_3.unique_no = mci=category_no3
left join(
select product_id,
count(0) count
from t2 pprod
inner join t3 pinfo on pinfo.promotion_id = pprod.promotion_idmysql面试题sql优化
and pprod.is_enable =1
and ppinfo.is_enable=1
and pinfo.belong_t0 =1
d_time >=now()
and not (
d_time>'2018-12-05 00:00:00'
)group by pprod.product_id
)as pc on pc.product_id = mci.product_id
where mci.is_enable =0
and mciodifty_type in ('1', '5', '6')
and (pc.count =0 unt isnull ) limit 0,5;
执⾏计划
2.场景解析
本例的SQL查询中有⼀个⼦查询,⼦查询被当成成驱动表,产⽣了auto_key,通过SQL进⾏进⾏测试,验证主要是(pc.count = 0或pc.count为null)会影响到整个SQL 的性能,需要进⾏⽐较改写。
3.场景优化
⾸先我们可以单独思考(pc.count = 0或pc.count为null)如何进⾏优化?先写⼀个类似的SQL
Select col from test where col =100 or col is null;
+--------+
| col    |
+--------+
|    100 |
|  NULL |
+--------+
2 rows in set (0.00 sec)
这个时候我们看到的其实是同⼀个列,但对应不同的值,这种情况可以利⽤case when进⾏转换。
Select col From test where case when col is null then 100 else col =100 end;
+--------+
| col    |
+--------+
|    100 |
|  NULL |
+--------+
options翻译成中文2 rows in set (0.00 sec)
再回到原始SQL进⾏改写。
select
....
指针数组存储字符串....
from
t1 as mci
left join t1 as ccv2_1 on ccv2_1.unique_no = mci=category_no1
left join t1 as ccv2_2 on ccv2_2.unique_no = mci=category_no2
left join t1 as ccv2_3 on ccv2_3.unique_no = mci=category_no3
left join(
select product_id,
count(0) count
from t2 pprod
inner join t3 pinfo on pinfo.promotion_id = pprod.promotion_id
and pprod.is_enable =1
and ppinfo.is_enable=1
and pinfo.belong_t0 =1
d_time >=now()
and not (
d_time>'2018-12-05 00:00:00'
)group by pprod.product_id
)as pc on pc.product_id = mci.product_id
网站设计公司网where mci.is_enable =0
and mciodifty_type in ('1', '5', '6')
and case unt is null then 0 unt end=0 limit 0,5;
可以抛光优化后的SQL⽐原始SQL快了30秒,执⾏效率提升约50倍。
案例三:优化关联SQL OR条件
1.待优化场景
SELECT user_msg.msg_id AS ‘msg_id’, t AS ‘msg_content’, …
FROM user_msg
LEFT JOIN user ON user_msg.user_id = user.user_id
LEFT JOIN group ON up_id = up_id
WHERE _modified >= date_sub('2018-03-29 09:31:44', INTERVAL30SECOND)
_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
2.场景解析
我们仔细分析上述查询语句,发现虽然业务逻辑只需要查询半分钟内修改的数据,但执⾏过程却必须对所有的数据进⾏关联操作,带来的性能损失。
3.场景优化
我们对原始SQL进⾏分解操作,第⼀部分sql-01如下:
SELECT user_msg.msg_id AS ‘msg_id’, t AS ‘msg_content’, …
FROM user_msg
LEFT JOIN user ON user_msg.user_id = user.user_id
LEFT JOIN group ON up_id = up_id
WHERE _modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND) sql-01以user_msg表为驱动,使⽤gmt_modified索引过滤最新数据。
第⼆部分sql-02如下:
java面试选择题
SELECT user_msg.msg_id AS ‘msg_id’, t AS ‘msg_content’, …
FROM user_msg
LEFT JOIN user ON user_msg.user_id = user.user_id
LEFT JOIN group ON up_id = up_id
_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)
sql-02以⽤户为驱动表,msg user_id的索引过滤⾏很好。
第三部分sql-03如下:
SELECT user_msg.msg_id AS ‘msg_id’, t AS ‘msg_content’, …
FROM user_msg
LEFT JOIN user ON user_msg.user_id = user.user_id
LEFT JOIN group ON up_id = up_id
_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND) sql-03以group为驱动表,使⽤gmt_modified索引过滤最新数据。
总结
MySQL OR条件优化的常见场景主要有以下情况:
1,相同列可以使⽤IN进⾏代替
2,不同列及复杂的情况下,可以使⽤union all进⾏分离
3,关联SQL OR条件
我们需要结合实际场景,分析优化。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。