mysql 中的存储过程太慢
Stored procedure is too slow in mysql
我有一个例程。但是太慢了。我怎样才能改进查询?
我的记录:http://www.sqlfiddle.com/#!9/14cceb/1/0
我的查询:
CREATE DEFINER = 'root'@'localhost'
PROCEDURE example.ssa()
BEGIN
drop table if exists gps_table;
drop table if exists exam_datas;
CREATE TEMPORARY TABLE gps_table(ID int PRIMARY KEY AUTO_INCREMENT,timei
int,
trun_date_time datetime, tadd_meter int, tin_here int null);
insert into gps_table(timei,trun_date_time,tadd_meter,tin_here) select
imei, run_date_time, add_meter, in_here from example_table;
CREATE TEMPORARY TABLE exam_datas(ID int PRIMARY KEY AUTO_INCREMENT,vimei
int, vbas_run_date_time datetime, vbit_run_date_time datetime, vdifff int);
select tin_here from gps_table limit 1 into @onceki_durum;
select count(id) from gps_table into @kayit_sayisi;
set @i = 1;
set @min_mes = 0;
set @max_mes = 0;
set @frst_id = 0;
set @imei = 0;
set @run_date_time = '0000-00-00 00:00:00';
set @run_date_time2 = '0000-00-00 00:00:00';
myloop: WHILE (@i <= @kayit_sayisi) DO
select tin_here from gps_table where id = @i into @in_here_true;
if (@in_here_true = 1) then
select id,trun_date_time, tadd_meter from gps_table where id = @i into @frst_id,@run_date_time2, @min_mes;
select id from gps_table where id > @frst_id and tin_here =0 order by id asc limit 1 INTO @id;
SET @id = @id-1;
select id, timei, trun_date_time, tadd_meter from gps_table
where id = @id and tin_here =1 limit 1 into @i, @imei, @run_date_time, @max_mes;
if(@i-@frst_id>3) then
set @i:=@i+1;
insert into exam_datas(vimei,vbas_run_date_time,vbit_run_date_time,vdifff) Values (@imei, @run_date_time2, @run_date_time, @max_mes-@min_mes);
SELECT * FROM exam_datas;
SET @asd =1;
elseif 1=1 then
set @i:=@i+1;
End if;
ELSEIF 1=1
THEN SET @i:=@i+1;
End if;
IF (@i = @kayit_sayisi)
THEN set @tamam =1; LEAVE myloop;
END IF;
END WHILE myloop;
select DISTINCT * from exam_datas;
drop table if exists exam_datas;
drop table if exists gps_table;
END
我需要:id= 6 首先为真且 id= 11 last_true
firs_trure - last_true = 304-290= 14
- id=14 第一个为真且 id=18 last_true
firs_true - last_true = 332-324= 8
这个例程太慢了。
MySql 版本是 5.7 table.
有 2 百万条记录
更新:
查询在这里。 HERE
谢谢@LukStorms
有可能在 1 个查询中得到这样的结果。
从而避免对记录进行 WHILE 循环。
此示例在不使用 window 函数的情况下工作。只需在查询中使用变量来计算排名。然后用于获取组的最小值和最大值。
select
imei,
min(run_date_time) as start_dt,
max(run_date_time) as stop_dt,
max(add_meter) - min(add_meter) as diff
from
(
select imei, id, run_date_time, add_meter, in_here,
case
when @prev_imei = imei and @prev_ih = in_here then @rnk
when @rnk := @rnk + 1 then @rnk
end as rnk,
@prev_imei := imei as prev_imei,
@prev_ih := in_here as prev_ih
from example_table t
cross join (select @rnk := 0, @prev_ih := null, @prev_imei := null) vars
order by imei, id, run_date_time
) q
where in_here = 1
group by imei, rnk
having count(*) > 4
order by imei, min(id);
在程序中,此类查询可用于填充最终的临时 table。
对 db<>fiddle here
的测试
我有一个例程。但是太慢了。我怎样才能改进查询?
我的记录:http://www.sqlfiddle.com/#!9/14cceb/1/0
我的查询:
CREATE DEFINER = 'root'@'localhost'
PROCEDURE example.ssa()
BEGIN
drop table if exists gps_table;
drop table if exists exam_datas;
CREATE TEMPORARY TABLE gps_table(ID int PRIMARY KEY AUTO_INCREMENT,timei
int,
trun_date_time datetime, tadd_meter int, tin_here int null);
insert into gps_table(timei,trun_date_time,tadd_meter,tin_here) select
imei, run_date_time, add_meter, in_here from example_table;
CREATE TEMPORARY TABLE exam_datas(ID int PRIMARY KEY AUTO_INCREMENT,vimei
int, vbas_run_date_time datetime, vbit_run_date_time datetime, vdifff int);
select tin_here from gps_table limit 1 into @onceki_durum;
select count(id) from gps_table into @kayit_sayisi;
set @i = 1;
set @min_mes = 0;
set @max_mes = 0;
set @frst_id = 0;
set @imei = 0;
set @run_date_time = '0000-00-00 00:00:00';
set @run_date_time2 = '0000-00-00 00:00:00';
myloop: WHILE (@i <= @kayit_sayisi) DO
select tin_here from gps_table where id = @i into @in_here_true;
if (@in_here_true = 1) then
select id,trun_date_time, tadd_meter from gps_table where id = @i into @frst_id,@run_date_time2, @min_mes;
select id from gps_table where id > @frst_id and tin_here =0 order by id asc limit 1 INTO @id;
SET @id = @id-1;
select id, timei, trun_date_time, tadd_meter from gps_table
where id = @id and tin_here =1 limit 1 into @i, @imei, @run_date_time, @max_mes;
if(@i-@frst_id>3) then
set @i:=@i+1;
insert into exam_datas(vimei,vbas_run_date_time,vbit_run_date_time,vdifff) Values (@imei, @run_date_time2, @run_date_time, @max_mes-@min_mes);
SELECT * FROM exam_datas;
SET @asd =1;
elseif 1=1 then
set @i:=@i+1;
End if;
ELSEIF 1=1
THEN SET @i:=@i+1;
End if;
IF (@i = @kayit_sayisi)
THEN set @tamam =1; LEAVE myloop;
END IF;
END WHILE myloop;
select DISTINCT * from exam_datas;
drop table if exists exam_datas;
drop table if exists gps_table;
END
我需要:id= 6 首先为真且 id= 11 last_true
firs_trure - last_true = 304-290= 14
- id=14 第一个为真且 id=18 last_true
firs_true - last_true = 332-324= 8
这个例程太慢了。
MySql 版本是 5.7 table.
有 2 百万条记录更新:
查询在这里。 HERE
谢谢@LukStorms
有可能在 1 个查询中得到这样的结果。
从而避免对记录进行 WHILE 循环。
此示例在不使用 window 函数的情况下工作。只需在查询中使用变量来计算排名。然后用于获取组的最小值和最大值。
select
imei,
min(run_date_time) as start_dt,
max(run_date_time) as stop_dt,
max(add_meter) - min(add_meter) as diff
from
(
select imei, id, run_date_time, add_meter, in_here,
case
when @prev_imei = imei and @prev_ih = in_here then @rnk
when @rnk := @rnk + 1 then @rnk
end as rnk,
@prev_imei := imei as prev_imei,
@prev_ih := in_here as prev_ih
from example_table t
cross join (select @rnk := 0, @prev_ih := null, @prev_imei := null) vars
order by imei, id, run_date_time
) q
where in_here = 1
group by imei, rnk
having count(*) > 4
order by imei, min(id);
在程序中,此类查询可用于填充最终的临时 table。
对 db<>fiddle here
的测试