mariadb-sql查询性能或优化

lnlaulya  于 2021-07-29  发布在  Java
关注(0)|答案(1)|浏览(551)

我有一个存储过程。性能方面有点问题。我想提高存储过程的性能,但我不知道该怎么办。我的数据库里大约有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

我这里有一个数据库示例。
我的.cnf有所改进,但在性能方面仍有困难。这个查询有什么问题?我能换什么?
从现在开始谢谢你。
编辑:
服务器版本:10.1.41-mariadb-mariadb server
我有索引。我在创建测试数据时忘记了添加索引。

liwlm1x9

liwlm1x91#

这到底是什么?

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

至少可以通过改为

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

那么,这会不会导致对2,21,20,12。。。如果工作日是“2”?
这些可能对你有用 ss :

(car_id, inst_id, start_time)
(inst_id, car_id, finish_time)
``` `LIMIT 1` 没有 `ORDER BY` 导致某个随机行被返回?是 `LIMIT` 冗余?或者是一个 `ORDER BY` 需要?
建议你找些时间安排——不清楚是哪一个 `SELECTs` 占用cpu最多。
如果 `PRIMARY KEY` 的 `cars` 是 `id` 那为什么要测试 `inst_id` 以及 `active` ? 哎呀!你似乎没有一个pk `cars` ! 请确认每个表都有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')

另外,要注意不等式测试,它可能会导致一些你不想要的边缘情况。
不要使用 `(m,n)` 在 `FLOAT` (例如,float(11,7));它做的是不必要的舍入。此外,纬度/液化天然气的小数点不能为7位,除非非常接近赤道且经度=0。更多关于精度:http://mysql.rjweb.org/doc.php/latlng#representation_choices
在你清理了这些,并提供了要求的信息,我会再看看。

相关问题