MySQL的经典SQL优化12例(更新于2023年12月28日)
下列优化的SQL案例,区别于平常加SQL索引的方法优化,大部分都是通过改写SQL语句方法优化,都是日常优化线上慢SQL的实际案例,有比较好的代表性(思路和方法),也是对自己这些年来做SQL优化的总结,对后面优化SQL有很好的提示和借鉴,案例会持续更新中。
说明:
最近优化慢SQL,执行计划错误和OR条件查询优化实战经验,提供优化SQL思路和方法:
1,利用exists来优化SQL(利用exists减少回表查询次数和确定驱动表)
2,OR语句优化(OR条件,字段有索引,无法使用索引的)
案例1:
SELECT sum( CASE WHEN ols.check_status NOT IN ( 2, 3, 4 ) THEN 1 WHEN ols.check_status IS NULL THEN 1 END ) AS
lesson_num, sum( ols.check_status = 1 ) AS attend_num FROM ol_live_student_time_chapter_list olstcl LEFT JOIN
ol_live_student ols ON olstcl.live_student_id = ols.id inner JOIN ol_user u ON u.id = olstcl.user_id
WHERE olstcl.class_course_type = '2' AND olstcl.attend_status <> 4
AND olstcl.start_time >= 1621526400 AND olstcl.start_time < 1621612799 AND u.is_test_user = '0' AND
counselor_id = '796' AND u.pay_status = '0' AND u.type = '1' AND u.STATUS = '1';
执行超过2.2秒,执行计划如下,从执行计划看:返回的rows也很少。key里用到了索引,按理说这个SQL是最优的SQL,没有优化的空间
但实际查看ol_user表,表有430万条数据,核心还是查询ol_user表的数据,如果能去掉ol_user表查询,就更好,如果不能去掉,能有其他优化方法:
通过仔细分析3个表,各个条件查询查出的数据:
select count(*) ol_live_student_time_chapter_list olstcl where olstcl.start_time>= 1621526400 AND
olstcl.start_time< 1621612799 and olstcl.class_course_type = '2' AND olstcl.attend_status <> 4
发现ol_live_student_time_chapter_list 查询,这个时间查出只有8000多条。而查询oL_user表查询:
select count(*) from ol_user u where u.is_test_user = '0' AND counselor_id = '796' AND u.pay_status = '0'
AND u.type = '1' AND u.STATUS = '1'
查出300多条,但仔细计划显示:Using intersect(pay_status_user,counselor_id,type,is_test_user); Using where; Using index。 的确用很多索引,
这样看,表面看执行计划没问题,但实际看一下,这个ol_user表查询,其实只是一个条件,ol_user没有字段在select查出显示,从某种意义上讲,只需要查出符合条件的就可以,如果满足其中
一个就返回效率是否更高,不需要每个条件都查完,这样我们完全可以用EXISTS 替换inner join 来提高查询效率,SQL修改如下:
SELECT sum( CASE WHEN ols.check_status NOT IN ( 2, 3, 4 ) THEN 1 WHEN ols.check_status IS NULL THEN 1 END ) AS
lesson_num, sum( ols.check_status = 1 ) AS attend_num FROM ol_live_student_time_chapter_list olstcl LEFT JOIN
ol_live_student ols ON olstcl.live_student_id = ols.id WHERE olstcl.class_course_type = '2' AND
olstcl.attend_status <> 4 AND olstcl.start_time >= 1621526400 AND olstcl.start_time < 1621612799 and
EXISTS (select 1 from ol_user u where u.is_test_user = '0' AND u.counselor_id
= '796' AND u.pay_status = '0' AND u.type = '1' AND u.STATUS = '1' and u.id = olstcl.user_id) ;
使用优化的SQL,时间只有0.9秒左右
优化原理: 利用 EXISTS 来替换 inner join,减少查询循环回表次数,提高效率。
案例2:
select count(distinct u.id) from ol_user u left join ol_user_related_info uri on u.id = uri.user_id where
u.type=1 and u.status =1 and u.pay_status=0 and uri.recovery_time_no_pay>=1622649600 and
uri.recovery_time_no_pay<1622736000 and u.counselor_id in (403);
执行超过1.3秒,执行计划如下:
从这里看:查出ol_user的u.id,distinct汇总,而ol_user_related_info 是left join,仔细看逻辑,虽然是left join,但有uri.recovery_time_no_pay条件,就这个left join 可以改成inner join
可以改成:
select count(distinct uri.user_id) from ol_user u inner join ol_user_related_info uri on u.id = uri.user_id
where u.type=1 and u.status =1and u.pay_status=0 and uri.recovery_time_no_pay>=1622649600 and
uri.recovery_time_no_pay<1622736000 and u.counselor_id in (403);
修改完,2者的执行效率,查不多,改了也没优化,如上面的优化,我们知道ol_user表的数据量太大,要减少回表的查询,
该SQL就可以改成exists查询,如下:
select count(distinct uri.user_id) from ol_user_related_info uri where uri.recovery_time_no_pay>=1622649600
and uri.recovery_time_no_pay<1622736000 and exists (select 1 from ol_user u where u.id = uri.user_id and
u.type=1 and u.status =1 and u.pay_status=0 and u.counselor_id in (403) )
改成这样,SQL执行只需0.6秒左右,未加索引,改写SQL,left join修改成 inner join,再改成exists查询。
案例3
SELECT f.flow_type,count(1) as num FROM `ol_admin_flow` `f` LEFT JOIN `ol_admin_flow_node` `n` ON `f`.`flowid`=
`n`.`flowid` WHERE( `n`.`adminid` = 7417 OR `f`.`post_adminid` = 7417 ) GROUP BY `f`.`flow_type`;
执行超过2.5秒,post_adminid加索引,SQL也用不到索引,将or改写成 union all写法
select flow_type,sum(num) num from (SELECT f.flow_type,1 num FROM ol_admin_flow f LEFT JOIN ol_admin_flow_node n
ON f.flowid=n.flowid WHERE f.post_adminid = 7418 union all SELECT f.flow_type,1 num FROM ol_admin_flow f LEFT
JOIN ol_admin_flow_node n ON f.flowid=n.flowid WHERE n.adminid = 7418 ) a group by flow_type
改成这样写法后。SQL效率大幅提升,查询只需0.3秒
案例4
SELECT au.GROUP group_id,sum(IF (o.STATUS = 3 AND o.attach_pay_time BETWEEN 1625068800 AND 1627747199 AND
o.rebate_time BETWEEN 1625068800 AND 1627747199, 0, oap.price ) ) real_renewal_money, sum(IF ( o.STATUS = 3
AND o.attach_pay_time BETWEEN 1625068800 AND 1627747199 AND o.rebate_time BETWEEN 1625068800 AND
1627747199, 0, oap.order_count ) ) renewal_num FROM `ol_order_attach_pay` `oap` INNER JOIN
`ol_order` `o` IGNORE INDEX ( idx_pay_time_type ) ON `o`.`order_number` = `oap`.`order_number` AND `o`.`status`
IN ( 1, 3 ) AND ( `o`.`attach_pay_time` >= 1625068800 AND `o`.`attach_pay_time` < 1627055999 ) AND
`o`.`package_course_type` = 1 INNER JOIN `online`.`ol_admin_user` `au` ON `oap`.`adminid` = `au`.`id` WHERE
`oap`.`status` = 1 AND `oap`.`adminid` IN ( 728, 818, 870, 1497, 2019, 2021,
2465, 2557, 2679, 3228, 3231, 3916, 3419, 3423, 3412, 3417, 3500, 4165,
477, 4163, 1030, 562 )
GROUP BY `au`.`group` LIMIT 100;
该SQL线上执行需要18秒以上,执行计划如下:
从执行计划看,慢的地方在查询ol_order的索引,有76万条。表中有以下索引:
KEY `attach_pay_time` (`attach_pay_time`) KEY `package_course_type` (`package_course_type`),表中有20多个索引,太多,真不想再建索引。但不加索引无法优化,用 force index 索引优化效果又不太好,一开始研发建立复合索引:KEY `idx_pay_time_type` (`attach_pay_time`,`package_course_type`), 按理应该优化,但实际优化效果不好,后续将复合索引改成:
KEY `idx_pay_time_type` (`package_course_type`,`attach_pay_time`),
加好后,执行计划如下,查询在0.5秒:
案例5
利用id主键来排序优化
select q.q_id, q.q_title from bbs_question q where q.app_id = 'xtep' and q.delete_flag = 0 and
( q.ban_flag is null or q.ban_flag = 0 )
and ( q.q_title like '%圆领%' or q.q_context like '%圆领%' ) order by q.create_time desc limit 10
优化说明:优化前因有OR和like查询,不好再建索引优化,查询需要2秒以上,因创建时间和主键自增长二者排序数据一致,order by q.create_time desc 改成 order by q.q_id desc ,SQL中create_time排序改成利用主键排序,优化后只需0.4秒。
案例6
利用全文索引优化
update sys_org_shop set path = REPLACE(path, '1806874642_1,6006991214_3,4006896323_4,4006910831_4,6006945801_6,
5007352247_5,', '1806874642_1,6006991214_3,4006896323_4,4006910831_4,6006945737_6,5007352247_5,'),operation='
1658136067459_method:SysOrgEnterprise.editOrgType' where path like '%1806874642_1,6006991214_3,4006896323_4,
4006910831_4,6006945801_6,5007352247_5,%' and app_id='dep'
该语句执行平均1.9秒,查询更新path字段,在path建索引,效果不大,而且必须使用前后的%,效率很低,只能在path建立全文索引,运MySQL的版本是
5.6的,MySQL5.6全文索引不支持中文,但这个字段只支持数字和“,”。对优化该SQL足够,like模糊查询字段建立全文索引优化。
alter table sys_org_shop add FULLTEXT idx_path(path)
优化后SQL如下;注意AGAINST的挂号里面的有一对"",否则全文查询的数据不对
update sys_org_shop set path = REPLACE(path, '1806874642_1,6006991214_3,4006896323_4,4006910831_4,6006945801_6,
5007352247_5,', '1806874642_1,6006991214_3,4006896323_4,
4006910831_4,6006945737_6,5007352247_5,'),
operation='1658136067459_method:SysOrgEnterprise.editOrgType' where
MATCH(`path`) AGAINST ('"1806874642_1,6006991214_3,4006896323_4,4006910831_4,6006945801_6,5007352247_5,"')
and app_id='dep'
案例7
利用普通索引优化like模糊查询
select t.id,t.title,t.text_info,t.create_user,t.create_time,t.app_id,t.flag,u.name from sys_img_text t,sys_user
u where t.create_user=u.sys_user_id and t.app_id = '3S' and t.title like '%27C01010%' and t.flag = 1 order
by t.create_time desc limit 5
该SQL执行计划:
查询先走的create_time排序索引,再查询数据,执行起来要38秒+,很慢,可以在title字段建全文索引查询,但MySQL版本是5.6,
不支持中文,建了如查询中文的就查不出来,这里有app_id 有索引,可以用这个索引做一下过滤,过滤后在title字段模糊查询会快很多。
修改SQL 如下:
select t.id,t.title,t.text_info,t.create_user,t.create_time,t.app_id,t.flag,u.name from sys_img_text t
force index(idx_app),sys_user u where t.create_user=u.sys_user_id and t.app_id = '3S' and t.title
like '%27C01010%' and t.flag = 1 orderby t.create_time desc limit 5
查询先过滤一层数据,在无全文索引情况下,增加force index(idx_app)强制索引查询,提高高查询效率,执行只需要0.011秒,
有几千倍的性能提升。
案例8
SQL在MySQL5.5执行正常,到了MySQL5.6和5.7执行一直很慢,执行查不出结果:(2023年3月31日补充案例)
SELECT
count( DISTINCT t1.seafarer_id ) AS hisNum,
count( DISTINCT t2.seafarer_id ) AS jyNum
FROM
cy_cy_qf t1
LEFT JOIN (
SELECT
t3.comp_id,
t3.seafarer_id,
t4.const_key,
t4.const_value
FROM
gt_cp t4
LEFT JOIN cy_cy_mf t3 ON t3.comp_id = t4.comp_id
AND t3.memo_kind_id = t4.const_key
WHERE
t3.comp_id = 'COMP2967'
AND t3.delete_flag = '0'
) t2 ON t1.comp_id = t2.comp_id
AND t1.seafarer_id = t2.seafarer_id
AND t2.const_value = '就医/看诊'
WHERE
t1.delete_flag = '0'
AND t1.comp_id = 'COMP2967'
SQL的执行计划
从这看出gt_cp t4,这个表扫描的行数很多,通过t1.seafarer_id = t2.seafarer_id 查询,comp_id的值都相等,无过滤性。优化能从gt_cp优化,同时如果distinct t2.seafarer_id查出的数量很多,如果有很多重复的数据,在关联嵌套循环时,要多次循环,可以考虑尽量把t2的子循环数据减少,同时减少seafarer_id的数,修改后SQL如下:
select count(distinct t1.seafarer_id) as hisNum,
count(distinct t2.seafarer_id) as jyNum
from
cy_cy_qf t1
left join
(select (distinct t3.seafarer_id) seafarer_id
from gt_cp t4
left join cy_cy_mf t3
on t3.comp_id = t4.comp_id and
t3.memo_kind_id = t4.const_key
where
t3.comp_id = 'COMP2967' and
t3.delete_flag = '0' and t4.const_value = '就医/看诊') t2
on t1.seafarer_id = t2.seafarer_id
where
t1.delete_flag = '0' and
t1.comp_id = 'COMP2967'
SQL修改如下后,执行从无法查出数据降到只需0.2秒,同时没有建任何索引,性能大幅提升。
案例9
SQL执行一直很慢,需要6秒才能有结果,SQL如下:(2023年4月25日补充案例)
SELECT
m.id,
m.comp_id,
m.vessel_id,
m.dept_id,
m.vessel_name,
m.device_id,
d.device_name,
m.order_type,
m.plan_date,
t.execution_content,
t.plan_content,
t.sp_out_store_id spOutStoreId,
t.ma_out_store_id maOutStoreId,
d.parent_device_id,
d.parent_device_name,
d.device_level_flag
FROM
mw_view m
LEFT JOIN mw_order t ON m.id = t.id
AND m.comp_id = t.comp_id
LEFT JOIN md_info d ON m.device_id = d.id
WHERE
1 = 1
AND m.comp_id = 'e98aab51fcd940f3b7aee670a2ea4207'
AND (
m.vessel_id = '570ca38b05344c5daa30d00fccae8512'
OR m.vessel_id = 'd66417caacdd46a4918619eee0239d50'
OR m.vessel_id = '5a67345cb19c4e449243423285c60550'
OR m.vessel_id = 'e34a6304d1cc4fbd962cf852a04bcba3'
OR m.vessel_id = '35c9f507cd9645338c45588f00f24b6f'
OR m.vessel_id = 'f668e782b2b14e58b5346998d9a3be75'
OR m.vessel_id = '455393531f28411c86eaab071685664b'
OR m.vessel_id = 'cf5b84600d38494aa97c1824666d2eca'
OR m.vessel_id = '5156d56d648f471eb5ac4173db63842c'
OR m.vessel_id = 'ee5d5d871f6045088c5b5817193d5962'
OR m.vessel_id = '2fe2b46255ca4cad855f2476af496d76'
OR m.vessel_id = '0aa93557f6794c13ab14a4a432c5b7ed'
OR m.vessel_id = 'a2d587d2247d4426bec020776226f827'
OR m.vessel_id = '18437c78e58e4768bcec849f0b7bc8c4'
OR m.vessel_id = '5415db21fa7e47629d6563885aea92b5'
OR m.vessel_id = '6c534cd5ebfd42159c3a852c078ccc99'
OR m.vessel_id = 'e2d6568bfd614f5a92d2c25c13d56c02'
OR m.vessel_id = 'e87f3c7b33de4779a8bd5ad4c9fab00c'
OR m.vessel_id = '7114381f6bf2467dac1cb26d4a56ca71'
OR m.vessel_id = '48af2c42c3284c76b88cf2f57d34dc35'
OR m.vessel_id = 'b2fd6818be5346399a8db6785db1b20e'
OR m.vessel_id = '1d11b69b76224b5cbef8dfc0f5d37dda'
OR m.vessel_id = 'dd96e7b0658043889b67378552f91950'
OR m.vessel_id = '6ede3b68b0aa4aed9f54c90162701a80'
OR m.vessel_id = 'bda55c44da6f4b28a79e0eb2451afe7b'
OR m.vessel_id = '561d8e443e234507b72177fd65e947d5'
OR m.vessel_id = '5d52046476164e84af8998496c2d1227'
)
AND ( m.order_type = 'delay' OR m.order_type = 'warn' )
AND (
m.status_flag = '00'
OR m.status_flag = '55'
OR m.status_flag = '45'
OR m.status_flag = '35'
OR m.status_flag = '07'
OR m.status_flag = '50'
OR m.status_flag = '40'
OR m.status_flag = '30'
)
ORDER BY
m.order_type,
m.vessel_name,
m.plan_date
LIMIT 0,
10;
查看执行计划,表中加了 idx_cvs(comp_id,vessel_id,status_flag)索引也没有用,特别vessel_id 是in太多数据,和业务开发聊,能否减少vessel_id 值,回答是不能减少,测试发现去掉一半的vessel_id 值,就很快,查询就只需要查询0.2秒内,那如果不减少值,怎么才能提高效率,有其他办法?
后来考虑是否把这个vessel_id 的值,分成2个SQL再Union all 起来,这样满足程序逻辑,又提高效率,测试的确可以,修改的SQL如下,SQL从以前的6秒降到0.2秒左右:
select * from (
SELECT
m.id,
m.comp_id,
m.vessel_id,
m.dept_id,
m.vessel_name,
m.device_id,
d.device_name,
m.order_type,
m.plan_date,
t.execution_content,
t.plan_content,
t.sp_out_store_id spOutStoreId,
t.ma_out_store_id maOutStoreId,
d.parent_device_id,
d.parent_device_name,
d.device_level_flag
FROM
mw_view m
LEFT JOIN mw_order t ON m.id = t.id
AND m.comp_id = t.comp_id
LEFT JOIN md_info d ON m.device_id = d.id
WHERE
1 = 1
AND m.comp_id = 'e98aab51fcd940f3b7aee670a2ea4207'
AND (
m.vessel_id in('570ca38b05344c5daa30d00fccae8512' ,
'd66417caacdd46a4918619eee0239d50' ,
'5a67345cb19c4e449243423285c60550' ,
'e34a6304d1cc4fbd962cf852a04bcba3' ,
'35c9f507cd9645338c45588f00f24b6f' ,
'f668e782b2b14e58b5346998d9a3be75' ,
'455393531f28411c86eaab071685664b' ,
'cf5b84600d38494aa97c1824666d2eca' ,
'5156d56d648f471eb5ac4173db63842c' ,
'ee5d5d871f6045088c5b5817193d5962' ,
'2fe2b46255ca4cad855f2476af496d76' ,
'0aa93557f6794c13ab14a4a432c5b7ed' ,
'a2d587d2247d4426bec020776226f827' ,
'18437c78e58e4768bcec849f0b7bc8c4'
)
)
AND ( m.order_type = 'delay' OR m.order_type = 'warn' )
AND (
m.status_flag = '00'
OR m.status_flag = '55'
OR m.status_flag = '45'
OR m.status_flag = '35'
OR m.status_flag = '07'
OR m.status_flag = '50'
OR m.status_flag = '40'
OR m.status_flag = '30'
)
union all
SELECT
m.id,
m.comp_id,
m.vessel_id,
m.dept_id,
m.vessel_name,
m.device_id,
d.device_name,
m.order_type,
m.plan_date,
t.execution_content,
t.plan_content,
t.sp_out_store_id spOutStoreId,
t.ma_out_store_id maOutStoreId,
d.parent_device_id,
d.parent_device_name,
d.device_level_flag
FROM
mw_view m
LEFT JOIN mw_order t ON m.id = t.id
AND m.comp_id = t.comp_id
LEFT JOIN md_info d ON m.device_id = d.id
WHERE
1 = 1
AND m.comp_id = 'e98aab51fcd940f3b7aee670a2ea4207'
AND (
m.vessel_id in(
'5415db21fa7e47629d6563885aea92b5' ,
'6c534cd5ebfd42159c3a852c078ccc99' ,
'e2d6568bfd614f5a92d2c25c13d56c02' ,
'e87f3c7b33de4779a8bd5ad4c9fab00c',
'7114381f6bf2467dac1cb26d4a56ca71' ,
'48af2c42c3284c76b88cf2f57d34dc35' ,
'b2fd6818be5346399a8db6785db1b20e' ,
'1d11b69b76224b5cbef8dfc0f5d37dda',
'dd96e7b0658043889b67378552f91950' ,
'6ede3b68b0aa4aed9f54c90162701a80' ,
'bda55c44da6f4b28a79e0eb2451afe7b' ,
'561d8e443e234507b72177fd65e947d5' ,
'5d52046476164e84af8998496c2d1227' )
)
AND ( m.order_type = 'delay' OR m.order_type = 'warn' )
AND (
m.status_flag = '00'
OR m.status_flag = '55'
OR m.status_flag = '45'
OR m.status_flag = '35'
OR m.status_flag = '07'
OR m.status_flag = '50'
OR m.status_flag = '40'
OR m.status_flag = '30'
)
) t
ORDER BY
t.order_type,
t.vessel_name,
t.plan_date
LIMIT 0,
10
案例10
该SQL执行2秒左右,优化方法: 改变驱动表SQL如下,从depot_transfer_goods 表改成查询depot_transfer 表,改变和减少驱动表行数,来优化SQL。(案例日期:2023年12月28日)
SELECT a.*, b.type, b.status, b.allotTime, b.from
FROM depot_transfer_goods a
INNER JOIN depot_transfer b ON a.evidenceNo = b.no
WHERE b.depotId = 1
AND b.deleteStatus = 0
AND a.deleteStatus = 0
AND b.type IN (1)
AND b.status IN (3)
AND b.createTime BETWEEN 1672502400 AND 1702223999
ORDER BY b.createTime DESC
LIMIT 0, 12
优化后0.2秒左右,
select a.*, b.type, b.status, b.allotTime, b.from from (
select * from depot_transfer b where createTime BETWEEN 1672502400 AND 1702223999
and b.depotId = 1
AND b.deleteStatus = 0
AND b.type IN (1)
AND b.status IN (3)
) b inner join depot_transfer_goods a on a.evidenceNo = b.no
ORDER BY b.createTime DESC
LIMIT 0, 12
案例11
改变SQL的关联字段来优化,该SQL执行5秒左右,优化方法:改变关联字段,因mysql优化引擎不能传递相等字段(没有谓词下推),将ON t8.materialCode = t.materialCode 改成 ON t8.materialCode = t6.materielCode ,
因t.materialCode,这t表是查询表,需t查询出来才能关联t8,改成实体表t6,性能更好 。 (案例日期:2023年12月28日)
SELECT t6.materielCode, t6.cargoOwnerCode, t6.depotCode
, CONCAT(t6.materielCode, '-', t6.cargoOwnerCode, '-', t6.depotCode) AS threeCode
, CAST(SYSDATE() AS DATE) AS outDate, t6.stockAvailable
, IF(t8.id, 1, 0) AS isHighProfit
FROM (
SELECT t1.materialCode, t1.shopId, t3.supplier_code
FROM oms_order_parent t
INNER JOIN oms_order_goods t1 ON t1.orderParentNo = t.orderNo
INNER JOIN cloud_shop t3 ON t3.id = t1.shopId
WHERE t.createTime >= 1699545600
AND t.warehouseCode = 'CK0001'
AND (t.returnStatus IN (1, 3, 5)
OR (t.returnStatus = 4
AND t.warehouseOutStatus = 2))
GROUP BY t1.materialCode, t.warehouseCode, t3.supplier_code
) t
INNER JOIN wms_depot_stock_collect t6
ON t6.materielCode = t.materialCode
AND t6.cargoOwnerCode = t.supplier_code
AND t6.depotCode = 'CK0001'
AND t6.stockAvailable <= 20
AND t6.commodityType != 2
LEFT JOIN customer_material_factor_recommend t8
ON t8.materialCode = t.materialCode
AND t8.factorType = 'HIGHPROFIT'
修改SQL,优化后0.42秒
SELECT t6.materielCode, t6.cargoOwnerCode, t6.depotCode
, CONCAT(t6.materielCode, '-', t6.cargoOwnerCode, '-', t6.depotCode) AS threeCode
, CAST(SYSDATE() AS DATE) AS outDate, t6.stockAvailable
, IF(t8.id, 1, 0) AS isHighProfit
FROM (
SELECT t1.materialCode, t1.shopId, t3.supplier_code
FROM oms_order_parent t
INNER JOIN oms_order_goods t1 ON t1.orderParentNo = t.orderNo
INNER JOIN cloud_shop t3 ON t3.id = t1.shopId
WHERE t.createTime >= 1699545600
AND t.warehouseCode = 'CK0001'
AND (t.returnStatus IN (1, 3, 5)
OR (t.returnStatus = 4
AND t.warehouseOutStatus = 2))
GROUP BY t1.materialCode, t.warehouseCode, t3.supplier_code
) t
INNER JOIN wms_depot_stock_collect t6
ON t6.materielCode = t.materialCode
AND t6.cargoOwnerCode = t.supplier_code
AND t6.depotCode = 'CK0001'
AND t6.stockAvailable <= 20
AND t6.commodityType != 2
LEFT JOIN customer_material_factor_recommend t8
ON t8.materialCode = t6.materielCode
AND t8.factorType = 'HIGHPROFIT'
案例12
该SQL执行8秒左右,还使用了like的%查询,优化方法:将like语句的查询作为in条件,不要使用关联,避免优化引擎走错误的执行计划。 (案例日期:2023年12月28日)
SELECT count(DISTINCT t2.channelId) AS channelIdNum, count(DISTINCT t2.districtId) AS districtIdNum
FROM (
SELECT t.customerCode, t.materialCode
FROM crm_behavior_recommend t
INNER JOIN erp_base_customer t6
ON t.customerCode = t6.customerCode
AND t6.isStaff = 0
WHERE t.createTime >= FROM_UNIXTIME(1701964800)
AND t.createTime <= FROM_UNIXTIME(1702051199)
AND t.behaviorType IN (2, 3)
UNION
SELECT t.buyerCode, t2.materialCode
FROM oms_order_parent t
INNER JOIN oms_order_picking t1 ON t.orderNo = t1.orderNo
INNER JOIN oms_order_goods t2 ON t2.orderParentNo = t.orderNo
INNER JOIN erp_base_customer t6
ON t.buyerCode = t6.customerCode
AND t6.isStaff = 0
WHERE t.createTime >= 1701964800
AND t.createTime <= 1702051199
AND t.returnStatus != 4
AND t1.returnStatus != 4
) t
INNER JOIN oms_material_basics t1 ON t.materialCode = t1.materialCode
INNER JOIN erp_base_customer t2
ON t.customerCode = t2.customerCode
AND t2.isStaff = 0
LEFT JOIN (
SELECT t.id, t.name_path AS newCategoryName, t.category_name AS categoryName, t.id_path
FROM `db_baseinfo`.xdnet_basic_category t
WHERE t.category_level = 5
) t7
ON t7.id = t1.newCategoryId
WHERE CONCAT(',', t7.id_path, ',') LIKE CONCAT('%,', 2394, ',%')
优化后0.3秒左右
select count(DISTINCT t1.channelId) AS channelIdNum, count(DISTINCT t1.districtId) AS districtIdNum from (
SELECT DISTINCT t2.channelId , t2.districtId,t1.newCategoryId
FROM (
SELECT t.customerCode, t.materialCode
FROM crm_behavior_recommend t
INNER JOIN erp_base_customer t6
ON t.customerCode = t6.customerCode
AND t6.isStaff = 0
WHERE t.createTime >= FROM_UNIXTIME(1702224000)
AND t.createTime <= FROM_UNIXTIME(1702310399)
AND t.behaviorType IN (2, 3)
UNION
SELECT t.buyerCode, t2.materialCode
FROM oms_order_parent t
INNER JOIN oms_order_picking t1 ON t.orderNo = t1.orderNo
INNER JOIN oms_order_goods t2 ON t2.orderParentNo = t.orderNo
INNER JOIN erp_base_customer t6
ON t.buyerCode = t6.customerCode
AND t6.isStaff = 0
WHERE t.createTime >= 1702224000
AND t.createTime <= 1702310399
AND t.returnStatus != 4
AND t1.returnStatus != 4
) t
INNER JOIN oms_material_basics t1 ON t.materialCode = t1.materialCode
INNER JOIN erp_base_customer t2
ON t.customerCode = t2.customerCode
AND t2.isStaff = 0
) t1
where t1.newCategoryId in (
SELECT t.id
FROM xdnet_basic_category t
WHERE t.category_level = 5 and CONCAT(',', t.id_path, ',') LIKE CONCAT('%,', 2394, ',%')
)
总结:
1,优化SQL,MySQL需要选择正确的驱动表,如果执行计划不正确,可用exists来明确驱动表
2,加复合索引,最好先测试执行效果,有时预想和实际不一样
MySQL的经典SQL优化12例(更新于2023年12月28日)的更多相关文章
- MySQL派生表(derived)优化一例
1.什么是派生表derived 关键字:子查询–>在From后where前的子查询 mysql; +----+-------------+------------+------+-------- ...
- (6)MySQL进阶篇SQL优化(MyISAM表锁)
1.MySQL锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源 (如 CPU.RAM.I/O 等)的抢占以外,数据也是一种供许多用户共享的资源.如何保证数 据并 ...
- GIS大讲堂内所有讲座的索引(更新至2008年6月26日)(转)
转自:http://www.cnblogs.com/xiexiaokui/archive/2008/11/20/1337934.html GIS大讲堂内所有讲座的索引(更新至2008年6月26日) ...
- 全国Uber优步司机奖励政策 (12月28日-1月3日)
本周已经公开奖励整的城市有:北 京.成 都.重 庆.上 海.深 圳.长 沙.佛 山.广 州.苏 州.杭 州.南 京.宁 波.青 岛.天 津.西 安.武 汉.厦 门,可按CTRL+F,搜城市名快速查找. ...
- 北京Uber优步司机奖励政策(12月28日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 武汉Uber优步司机奖励政策(12月28日到1月3日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 天津Uber优步司机奖励政策(12月28日到12月29日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 南京Uber优步司机奖励政策(12月28日到1月3日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 佛山Uber优步司机奖励政策(12月28日到1月3日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 青岛Uber优步司机奖励政策(12月28日到1月3日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
随机推荐
- web - 解决 formdata 打印空对象
获取单个值可以使用formData对象.get();而直接打印是看不到的.因为外界访问不到,你使用append方法后,对应的键值对就已经添加到表单里面了,你在控制台看到的是FormData原型,存储的 ...
- [转帖]mysql 里 CST 时区的坑
mysql 里 CST 时区的坑 一.问题简述 mysql 里 CST 时区是个非常坑的概念,因为在 mysql 里CST既表示中国也表示美国的时区.但是在Jdk代码里,CST 这个字符串被理解为Ce ...
- [转帖]How to Resolve ORA-3136 Inbound Connection Timed Out
https://logic.edchen.org/how-to-resolve-ora-3136-inbound-connection-timed-out/#:~:text=ORA-03136%3A% ...
- [转帖]Web技术(六):QUIC 是如何解决TCP 性能瓶颈的?
文章目录 一.QUIC 如何解决TCP的队头阻塞问题? 1.1 TCP 为何会有队头阻塞问题 1.2 QUIC 如何解决队头阻塞问题 1.3 QUIC 没有队头阻塞的多路复用 二.QUIC 如何优化T ...
- [转帖]如何部署windows版本的oswatcher
2017-02-22 没有评论 windows上也有os watcher:OSWFW. 目前支持的windows版本是: Windows XP (x86 & x64)Windows 7 (x8 ...
- [转帖]《Linux性能优化实战》笔记(一)—— 平均负载
最近在看极客时间的<Linux性能优化实战>课程,记录下学习内容. 一. 平均负载(Load Average) 1. 概念 我们都知道uptime命令的最后三列分别是过去 1 分钟.5 分 ...
- [转帖]xfs_repair命令详解
https://bbs.qunyingkeji.com/2052/ 1.现状 目前网上出现大量的主机输入输出错误,原因是由于主机文件系统损坏.一线人员大部分采用的是umont 和 mount的方式恢复 ...
- [转帖]Nginx性能优化详解
https://developer.aliyun.com/article/886146?spm=a2c6h.24874632.expert-profile.256.7c46cfe9h5DxWK 感觉文 ...
- expres实现登录与修改密码
登录模块 如果登录的时候,昵称在数据库中查询的是不唯一值.需要提示用户登录失败. 即使用户密码输入正确. 然后将该消息通知相关人员,立即进行排查问题. var express = require('e ...
- Dubbo3应用开发—Dubbo注册中心引言
Dubbo注册中心引言 什么是Dubbo注册中心 Dubbo的注册中心,是Dubbo服务治理的⼀个重要的概念,他主要用于 RPC服务集群实例的管理. 注册中心的运行流程 使用注册中心的好处 可以有效的 ...