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
join
s, 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?