繁体   English   中英

MariaDB - sql 查询性能或优化

[英]MariaDB - sql query performance or optimization

我有一个存储过程。 在性能方面有点问题。 我想提高存储过程的性能,但我不知道该怎么做。 我的数据库中有大约 300 万条记录。 当我一个一个地运行这个查询时,它的性能很好。 但是当 150 个人同时运行这个存储过程时,CPU 就会出现峰值。

例如,我创建了我的过程和表结构。

我的存储过程:

BEGIN
SELECT ss.car_route from person o
inner join car_time ss on ss.inst_id =o.inst_id  
and ss.start_time<=DATE_FORMAT(CURTIME(),'%H:%i')  AND  ss.finish_time>= date_format(curtime() ,'%H:%i') AND ss.car_id=carid
and ss.days like concat('%',(select WEEKDAY(now())+1),'%') 
where (o.car_id=carid or o.back_car_id=carid ) LIMIT 1 into @route_;
select sf.stop_service from car_comp sf 
inner join cars s on s.inst_id = sf.id and s.id=carid and s.active=1 limit 1
into @stop_ser;



if @route_ = 1 and @stop_ser=0 THEN

select DISTINCT ss.start_time,ss.finish_time ,o.id,o.name,r.photo, oh.state ,oh.datee,ss.car_route,
ifnull(bh.id,0) AS called,
ifnull(mh.excuse_id,0) AS excuse_id,
ifnull(o.latitude_1,0) AS latitude_1,
ifnull(o.longitude_1,0) AS longitude_1,
ifnull(o.latitude_2,0) AS latitude_2,
ifnull(o.longitude_2,0) AS longitude_2,
case when (ifnull(o.call_notify,0)=1 or ifnull(o.mes_notify,0)=1) then 1 else 0 end AS call_notify ,
ifnull(o.rownumber,0) AS rownumber,
ifnull(o.number_1,0) AS number_1,
ifnull(o.number_2,0) AS number_2,
ifnull(o.brownumber,0) AS brownumber,
ifnull(ROUND(o.notify_meter_1/2),0) AS notify_meter_1,
ifnull(ROUND(o.notify_meter_2/2),0) AS notify_meter_2
from person o
inner join car_time ss on ss.inst_id =o.inst_id and o.car_id=ss.car_id
and ss.start_time<=DATE_FORMAT(CURTIME(),'%H:%i')  AND  ss.finish_time>= date_format(curtime() ,'%H:%i')
and ss.days like concat('%',(select WEEKDAY(now())+1),'%')

LEFT JOIN notify_records bh ON bh.table_id=o.id AND bh.car_route=@route_
and bh.table_name='person' AND bh.notify=4 AND bh.car_id=o.car_id and bh.date_ >= CURDATE() and bh.date_ < CURDATE() + INTERVAL 1 DAY 

left join  person_records oh   on  oh.person_id=o.id
and oh.car_id=o.car_id
and date_format(oh.datee,'%H:%i') >=ss.start_time
and date_format(oh.datee,'%H:%i') <=ss.finish_time
AND oh.car_route= @route_
and
oh.id in(select max(id) from person_records
where date_time >= CURDATE() and date_time < CURDATE() + INTERVAL 1 DAY and car_id = carid and car_id = carid
GROUP by person_id
)
left join inst ok on o.inst_id = ok.id and o.car_id=carid
left join excuse_records mh on mh.person_id=o.id and mh.date_time >= CURDATE() and mh.date_time < CURDATE() + INTERVAL 1 DAY and (mh.car_route=ss.car_route)
left join photo_ r on r.table_id = o.id and r.table_name = 'person'
where
(ss.car_route=o.cars_route_ or o.cars_route_=3) and

o.car_id = carid and o.active=1
AND o.work_time=ss.work_time;


elseif @route_ = 2 and @stop_ser=0 then

select DISTINCT ss.start_time,ss.finish_time ,o.id,o.name,r.photo, oh.state ,oh.datee,ss.car_route,
ifnull(bh.id,0) AS called,
ifnull(mh.excuse_id,0) AS excuse_id,
ifnull(o.latitude_1,0) AS latitude_1,
ifnull(o.longitude_1,0) AS longitude_1,
ifnull(o.latitude_2,0) AS latitude_2,
ifnull(o.longitude_2,0) AS longitude_2,
case when (ifnull(o.call_notify,0)=1 or ifnull(o.mes_notify,0)=1) then 1 else 0 end AS call_notify ,
ifnull(o.rownumber,0) AS rownumber,
ifnull(o.number_1,0) AS number_1,
ifnull(o.number_2,0) AS number_2,
ifnull(o.brownumber,0) AS brownumber,
ifnull(ROUND(o.notify_meter_1/2),0) AS notify_meter_1,
ifnull(ROUND(o.notify_meter_2/2),0) AS notify_meter_2
from person o
inner join car_time ss on ss.inst_id =o.inst_id and o.back_car_id=ss.car_id
and ss.start_time<=DATE_FORMAT(CURTIME(),'%H:%i')  AND  ss.finish_time>= date_format(curtime() ,'%H:%i')
and ss.days like concat('%',(select WEEKDAY(now())+1),'%')
LEFT JOIN notify_records bh ON bh.table_id=o.id AND bh.car_route=@route_
and bh.table_name='person' AND bh.notify=4 AND bh.car_id=o.back_car_id and bh.date_ >= CURDATE() and bh.date_ < CURDATE() + INTERVAL 1 DAY  
left join  person_records oh   on  oh.person_id=o.id
and oh.car_id=o.back_car_id and oh.car_route=2
and date_format(oh.datee,'%H:%i') >=ss.start_time
and date_format(oh.datee,'%H:%i') <=ss.finish_time
AND oh.car_route= @route_
and
oh.id in (select max(id) from person_records
where date_time >= CURDATE() and date_time < CURDATE() + INTERVAL 1 DAY and car_id = carid
GROUP by person_id
)
left join inst ok on o.inst_id = ok.id and o.car_id=carid
left join excuse_records mh on mh.person_id=o.id and mh.date_time >= CURDATE() and mh.date_time < CURDATE() + INTERVAL 1 DAY and (mh.car_route=ss.car_route)
left join photo_ r on r.table_id = o.id and r.table_name = 'person'
where
(ss.car_route=o.cars_route_ or o.cars_route_=3) and

o.back_car_id = carid and o.active=1
AND o.work_time=ss.work_time;


END IF;


end

我这里有一个数据库示例。

我对 my.cnf 进行了改进,但性能仍然存在困难。 这个查询有什么问题? 我能改变什么?

从现在开始谢谢你。

编辑:

服务器版本:10.1.41-MariaDB - MariaDB 服务器

我有索引。 我在创建测试数据时忘记添加索引。

这是什么鬼?

ss.days like concat('%',(select WEEKDAY(now())+1),'%')

至少可以通过更改为

ss.days like concat('%',WEEKDAY(now()),'%')

而且,如果 WEEKDAY 是“2”,这不会导致检查 2、21、20、12,...吗?

这些可能对ss有用:

(car_id, inst_id, start_time)
(inst_id, car_id, finish_time)

没有ORDER BYLIMIT 1会导致返回一些随机行? LIMIT是多余的吗? 还是需要ORDER BY

建议您获取一些时间 - 哪个SELECTs消耗的 CPU 最多并不明显。

如果carsPRIMARY KEYid ,那么为什么要测试inst_idactive 哎呀! 你好像没有cars PK。 请确认每个表都有一个 PK。

多余的:

              and  car_id = carid
              and  car_id = carid

为什么两次? 这些列在哪些表中? 请限定列,以便我们了解发生了什么。

@stop_ser=0时,程序什么都不做? 在这种情况下,请先执行该测试,这样您就可以避免计算@route

start_time更改为数据类型TIME 那么你可以摆脱DATE_FORMAT

      and  ss.start_time<=DATE_FORMAT(CURTIME(),'%H:%i')
      AND  ss.finish_time>= date_format(curtime() ,'%H:%i')

另外,请注意不等式测试,它可能会导致一些您不想要的边缘情况。

不要在FLOAT上使用(m,n) (例如,float(11,7)); 它会进行不必要的舍入。 此外,除了非常靠近赤道和经度 = 0 之外,您无法获得 7 个小数位的 lat/lng。 更多关于精度: http://mysql.rjweb.org/doc.php/latlng#representation_choices

在您清理完这些并提供所需的信息后,我会再看一下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM