暂无图片
分享
黄伟波
2021-03-23
MySQL慢sql优化问题

该sql耗时140s,执行计划如下:
image.png

t1表上的条件区分度不高,均不适合做索引,请问下有什么好的优化意见。

数据量如下:
image.png

收藏
分享
9条回答
默认
最新
gelyon

如果三个表的左外连接改为inner join,并且t3.customer建立索引,t2.order_release和t1.id都建立索引,并以t3表作为驱动表,效果可能会好些。

暂无图片 评论
暂无图片 有用 0
打赏 0
黄伟波

嗯,只查t3的id是快很多,但是因为是左连接导致结果不一致了

暂无图片 评论
暂无图片 有用 0
打赏 0
chengang

where 条件上有T3 所以和T3的关联可以直接改为inner join吧。

暂无图片 评论
暂无图片 有用 0
打赏 0
黄伟波

不能的,我就是这样改的,大概是这样:
select xxx from
t1
left join t2 on t1.id=t2.shipment
left join (select id from t3 where t3.customer=xxx) tt3 on tt3.id=t2.order_release
where
t1.xxxx
因为t3的id是主键,所以快很多,但是结果是不一致的

暂无图片 评论
暂无图片 有用 0
打赏 0
杨明翰

where子句中有条件t3.customer ,这种null-rejecting的情况是可以转换成inner join的
t2.order_release 建索引或者建(order_release,shipment)的组合索引
t3 (customer,id) 组合索引

用子查询的方式改写 from t1 where …… and id in
(select t2. shipment from t2 join t3 where t3.id=t2.order_release and t3.customer=…)

不用加distinct

暂无图片 评论
暂无图片 有用 0
打赏 0
黄伟波

是改成如下sql?我看了执行计划和原来是一样的。

SELECT DISTINCT
	t1.id,
	t1.shipment_no,
	t1.vehicle_no,
	t1.driver1_name,
	DATE_FORMAT( t1.latest_pickup_time, '%Y-%m-%d' ) AS latest_pickup_date,
	DATE_FORMAT( t1.latest_pickup_time, '%H:%i' ) AS latest_pickup,
	t1.latest_pickup_time,
	t1.version,
	t1.domain_name,
	t1.insert_user 
FROM
	fsl_shipment t1  
WHERE
	t1.project_code = 'DD' 
	AND t1.shipment_no IS NOT NULL 
	AND t1.shipment_status IN ( '18', '20' ) 
	AND t1.is_a_shipment = 'N' 
	AND t1.sendncicflag IS NULL 
	AND t1.custom_type IN (	'0','4')
	AND t1.id in (select t2.shipment from fsl_order_movement_unit t2 join  fsl_order_release t3 where  t2.order_release = t3.id and t3.customer = '30874729619931136' )

复制

image.png

暂无图片 评论
暂无图片 有用 0
打赏 0
杨明翰
不需要DISTINCT了
SELECT 
	t1.id,
	t1.shipment_no,
	t1.vehicle_no,
	t1.driver1_name,
	DATE_FORMAT( t1.latest_pickup_time, '%Y-%m-%d' ) AS latest_pickup_date,
	DATE_FORMAT( t1.latest_pickup_time, '%H:%i' ) AS latest_pickup,
	t1.latest_pickup_time,
	t1.version,
	t1.domain_name,
	t1.insert_user 
FROM
	fsl_shipment t1  
WHERE
	t1.project_code = 'DD' 
	AND t1.shipment_no IS NOT NULL 
	AND t1.shipment_status IN ( '18', '20' ) 
	AND t1.is_a_shipment = 'N' 
	AND t1.sendncicflag IS NULL 
	AND t1.custom_type IN (	'0','4')
	AND t1.id in (select t2.shipment from fsl_order_movement_unit t2 join  fsl_order_release t3 where  t2.order_release = t3.id and t3.customer = '30874729619931136' )


复制

另外 t2.order_release 建索引或者建(order_release,shipment)的组合索引
t3 (customer,id) 组合索引

暂无图片 评论
暂无图片 有用 0
打赏 0
黄伟波

跟业务部门确认后,因为这个sql比较重要,所以就不改写了,增加对t1表的时间限制条件,查最近15天,最终耗时16s

暂无图片 评论
暂无图片 有用 0
打赏 0
黄伟波
问题已关闭: 问题已经得到解决
暂无图片 评论
暂无图片 有用 0
打赏 0
回答交流
Markdown


请输入正文
提交
相关推荐
MySQL 搭建主从时,source还原数据中间退出几次,没有报错,数据量200G,怎么解决?
回答 1
已采纳
怎么个退出? 最好是有个截图建议用xtrabackup来搭建从库,速度比sql语句要快很多的
left join 左表5000多条数据右表6000多数据,查出的结果集是8000多条。但耗时竟然是30s左右??
回答 11
已采纳
可以使用showprofiles查看历史的sql命令,然后通过showprofileforqueryid命令得到该sql语句在每一步骤中的时间。因此如果某一个sql语句运行时间特别长,我们可以通过该条
关于主从报错
回答 1
建议mysql版本和把错误信息共享出来。除了nettimeout,网卡上也有net.ipv4.tcpfintimeout参考
如何使用更快的方法去重
回答 2
已采纳
做临时表,把结果放进去,定时刷新
请问各位大佬,mysql数据库key length计算问题:不存在not null约束为什么要加1?
回答 2
InnoDB需要为这个列的值保留一个字节来标记它是否为NULL,在计算索引长度时,没有NOTNULL约束,需要为这个可能的NULL标记预留一个字节。举个栗子,假设我们有一个VARCHAR(255)的列
mysql 字段设置默认值
回答 1
假设登录用户名为admin直接写default‘admin’不就可以了?
在mysql中,当子查询语句含有in或者exists关键字时会触发mysql内部查询转换成semi join,以下哪些属于semi join的策略?
回答 3
SEMIjoin简单来说就是外层的表的过滤依赖于内层的子查询语句作为过滤条件。MYSQL优化器为semi设置了如下几种的策略:DuplicateWeedoutstrategyFirstmatchStr
软考数据库系统工程师
回答 1
可以自学,但是要笔试考试,我有考过,可以一起交流一下www.mysqlmysql.com这个网站有我的联系方式 
用ODI做数据集成到MySQL的中间库,时间数据的源数据为12:42:00,到中间库之后变成00:42:00了,但21:42:00能正常转换成21:42:00,这是什么问题?
回答 2
已采纳
看看各个环节的日期格式,以及是否有日期格式化的操作。比如在12小时制转24小时制时,上午12:42:00会转换成0:42:00;而21:42:00则不需要转换
mysql中where条件语句加入子查询就挂机了,语句一定没有错,在sqlserver中运行正常
回答 1
sqlserver与mysql 处理子查询的算法是完全不一样的。你可以把explain发出来看看。在mysql8.0以前版本, 子查询很容易走DEPENDENTSUBQUERY&n