最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

數(shù)棧SQL優(yōu)化案例:OR條件優(yōu)化

2021-05-08 14:18 作者:袋鼠云  | 我要投稿

本文整理自:袋鼠云技術(shù)薈 | SQL優(yōu)化案例(2):OR條件優(yōu)化

數(shù)棧是云原生—站式數(shù)據(jù)中臺(tái)PaaS,我們?cè)趃ithub上有一個(gè)有趣的開源項(xiàng)目:https://github.com/DTStack/flinkx

FlinkX是一個(gè)基于Flink的批流統(tǒng)一的數(shù)據(jù)同步工具,既可以采集靜態(tài)的數(shù)據(jù),比如MySQL,HDFS等,也可以采集實(shí)時(shí)變化的數(shù)據(jù),比如MySQL binlog,Kafka等,是全域、異構(gòu)、批流一體的數(shù)據(jù)同步引擎,大家如果有興趣,歡迎來(lái)github社區(qū)找我們玩~

在MySQL中,同樣的查詢條件,如果變換OR在SQL語(yǔ)句中的位置,那么查詢的結(jié)果也會(huì)有差異,在較為復(fù)雜的情況下,可能會(huì)帶來(lái)索引選擇不佳的性能隱患,為了避免執(zhí)行效率大幅度下降的問(wèn)題,我們可以適當(dāng)考慮使用Union all 對(duì)查詢邏輯較為復(fù)雜的SQL進(jìn)行分離。

常見(jiàn)OR使用場(chǎng)景,請(qǐng)閱讀以下案例:

案例一:不同列使用OR條件查詢

1. 待優(yōu)化場(chǎng)景

SELECT .. .. ?FROM`t1` a WHERE a.token= '16149684' ? AND a.store_id= '242950' ? AND(a.registrationId IS NOT NULL ? AND a.registrationId<> '') ? ?OR a.uid= 308475 ? AND a.registrationId IS NOT NULL ? AND a.registrationId<> ''

執(zhí)行計(jì)劃

+--------------+-----------------------+-----------------+----------------+-------------------+-------------------+---------------+----------------+---------------------------------------------+ | 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 行記錄,花費(fèi) 5 ms。

2. 場(chǎng)景解析

從查詢條件中可以看出 token 和 uid 過(guò)濾性都非常好,但是由于使用了 or, 需要采用 index merge 的方法才能獲得比較好的性能。但在實(shí)際執(zhí)行過(guò)程中MySQL優(yōu)化器默認(rèn)選擇了使用registrationId 上的索引,導(dǎo)致 SQL 的性能很差。

3. 場(chǎng)景優(yōu)化

我們將SQL改寫成union all的形式。

SELECT ... ... FROM`t1` a WHERE a.token = '16054473' AND a.store_id = '138343' AND b.is_refund = 1 AND (a.registrationId IS NOT NULL AND a.registrationId <> '') union all SELECT ... ... FROM`t1` a where a.uid = 181579 AND a.registrationId IS NOT NULL AND a.registrationId <> ''


+--------------+-----------------------+-----------------+----------------+------------------------------+---------------+-------------------+------------------------------+----------------+------------------------------------+ | 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_sewsq.a.role_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 行記錄,花費(fèi) 5 ms。

通過(guò)對(duì)比優(yōu)化前后的執(zhí)行計(jì)劃,可以明顯看出,將SQL拆分成兩個(gè)子查詢,再使用union對(duì)結(jié)果進(jìn)行合并,穩(wěn)定性和安全性更好,性能更高。

案例二:同一列使用OR查詢條件

1. 待優(yōu)化場(chǎng)景

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 ?and pinfo.end_time >=now() ?and not ( ? pinfo.onshelv_time>'2019-06-30 00:00:00' ? or pinfo.end_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 mci.comodifty_type in ('1', '5', '6') and (pc.count =0 or pc.count isnull ) limit 0,5;

執(zhí)行計(jì)劃

2. 場(chǎng)景解析

本例的SQL查詢中有一個(gè)子查詢,子查詢被當(dāng)成驅(qū)動(dòng)表,產(chǎn)生了auto_key,通過(guò)SQL拆分進(jìn)行測(cè)試,驗(yàn)證主要是(pc.count =0 , or pc.count is null )會(huì)影響到整個(gè)SQL的性能,需要進(jìn)行比較改寫。

3. 場(chǎng)景優(yōu)化

首先我們可以單獨(dú)思考(pc.count =0 , or pc.count is null ) 如何進(jìn)行優(yōu)化?先寫一個(gè)類似的SQL

Select col from test where col =100 or col is null; +--------+ | col ? ?| +--------+ | ? ?100 | | ? NULL | +--------+ 2 rows in set (0.00 sec)

這個(gè)時(shí)候我們看到的其實(shí)是同一個(gè)列,但對(duì)應(yīng)不同的值,這種情況可以利用case when進(jìn)行轉(zhuǎn)換。

Select col From test where case when col is null then 100 else col =100 end; +--------+ | col ? ?| +--------+ | ? ?100 | | ? NULL | +--------+ 2 rows in set (0.00 sec)

再回到原始SQL進(jìn)行改寫。

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 ?and pinfo.end_time >=now() ?and not ( ? pinfo.onshelv_time>'2019-06-30 00:00:00' ? or pinfo.end_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 mci.comodifty_type in ('1', '5', '6') and case when pc.count is null then 0 else pc.count end=0 limit 0,5;

可以看出優(yōu)化后的SQL比原始SQL快了30秒,執(zhí)行效率提升約50倍。

案例三:優(yōu)化關(guān)聯(lián)SQL OR條件

1. 待優(yōu)化場(chǎng)景

SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, … FROM user_msg LEFT JOIN user ON user_msg.user_id = user.user_id LEFT JOIN group ON user_msg.group_id = group.group_id WHERE user_msg.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL30SECOND) OR user.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND) OR group.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)

2.場(chǎng)景解析

我們仔細(xì)分析上述查詢語(yǔ)句,發(fā)現(xiàn)雖然業(yè)務(wù)邏輯只需要查詢半分鐘內(nèi)修改的數(shù)據(jù),但執(zhí)行過(guò)程卻必須對(duì)所有的數(shù)據(jù)進(jìn)行關(guān)聯(lián)操作,帶來(lái)不必要的性能損耗。

3.場(chǎng)景優(yōu)化

我們對(duì)原始SQL進(jìn)行拆分操作,第一部分sql-01如下:

SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, … FROM user_msg LEFT JOIN user ON user_msg.user_id = user.user_id LEFT JOIN group ON user_msg.group_id = group.group_id WHERE user_msg.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)

sql-01以u(píng)ser_msg 表為驅(qū)動(dòng),使用gmt_modified 索引過(guò)濾最新數(shù)據(jù)。

第二部分sql-02如下:

SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, … FROM user_msg LEFT JOIN user ON user_msg.user_id = user.user_id LEFT JOIN group ON user_msg.group_id = group.group_id WHERE user.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)

ql-02以u(píng)ser為驅(qū)動(dòng)表,msg user_id 的索引過(guò)濾行很好。

第三部分sql-03如下:

SELECT user_msg.msg_id AS ‘msg_id’, user_msg.content AS ‘msg_content’, … FROM user_msg LEFT JOIN user ON user_msg.user_id = user.user_id LEFT JOIN group ON user_msg.group_id = group.group_id WHERE group.gmt_modified >= date_sub('2018-03-29 09:31:44', INTERVAL 30 SECOND)

sql-03以group為驅(qū)動(dòng)表,使用gmt_modified 索引過(guò)濾最新數(shù)據(jù)。

總結(jié)

MySQL OR條件優(yōu)化的常見(jiàn)場(chǎng)景主要有以下情況:

1、相同列可以使用IN進(jìn)行代替

2、不同列及復(fù)雜的情況下,可以使用union all 進(jìn)行分離

3、關(guān)聯(lián)SQL OR條件

我們需要結(jié)合實(shí)際場(chǎng)景,分析優(yōu)化。


數(shù)棧SQL優(yōu)化案例:OR條件優(yōu)化的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
广饶县| 炎陵县| 泰顺县| 临清市| 冷水江市| 锦州市| 阳城县| 锦屏县| 晋城| 高青县| 中超| 申扎县| 集贤县| 曲阳县| 南江县| 陆良县| 马公市| 武定县| 巴林左旗| 河南省| 读书| 颍上县| 新营市| 吐鲁番市| 阆中市| 政和县| 彭山县| 正阳县| 荃湾区| 赤水市| 天津市| 金沙县| 伊宁县| 九龙县| 夏邑县| 赤壁市| 六盘水市| 和平县| 获嘉县| 株洲市| 米泉市|