MySQL docs state that the time required for inserts has these approximate proportions:
Connecting: (3)
Sending query to server: (2)
Parsing query: (2)
Inserting row: (1 × size of row)
Inserting indexes: (1 × number of indexes)
Closing: (1)
In other words, if we use stored procedures to do inserts into a table without indexes, the deciding factor for the time required would simply be:
- Inserting row: (1 × size of row)
So I test with a stored procedure that made 2 million inserts:
create table t(i int)engine innodb;
delimiter $
create procedure f()begin
while @a<=2000000 do
insert t select null;
set@a=@a+1;
end while;
end$
delimiter ;
set@a=1;
begin;call f;commit;drop procedure f;
select count(*)from t;drop table t;
The query call f; takes 29.44 seconds.
Rolando suggests (below) to use a prepared statement, so I updated the stored procedure to use prepare:
create table t(i int)engine innodb;
delimiter $
create procedure f()begin
while @a<=2000000 do
execute e; # # # # # # # # # # # # # # changed insert statement
set@a=@a+1;
end while;
end$
delimiter ;
set@a=1;
prepare e from'insert t select null'; # # # # # # added prepare statement
begin;call f;commit;drop procedure f;
deallocate prepare e; # # # # # # # # # # # # # # added optional deallocate prepare statement
select count(*)from t;drop table t;
However, the query call f; now still takes 30.27 seconds.
It seems like there's no way to beat raw "begin + loop insert + commit" (unless we resort to file loading using load data infile).
However, if we insert using select joins, it only takes 6.28 seconds:
create table t(i int)engine innodb;
insert t select null
from(
select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10
)`10`
join(
select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10
)`100`
join(
select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10
)`1000`
join(
select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10
)`10k`
join(
select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10
)`100k`
join(
select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 10
)`1m`
join(
select 1 union select 2
)`2m`;
select count(*)from t;drop table t;
I'm using MySQL (though I suspect this isn't a MySQL-specific issue).
Why is "select join insert" so much faster than "loop insert"?
What's the explanation for this oddity?
preparebefore thewhileloop:prepare e from'insert t select null'and then I replaced the insert statement in the code above withexecute e(see the update), but then the timing is 31.23 seconds. As we can see, allocation and deallocation is done only once, but the performance is still slow. Do you know what's the explanation for this oddity? – Pacerier Apr 09 '15 at 04:01prepareexecute, but the performance is still slow. – Pacerier Apr 11 '15 at 17:39