:: DEVELOPER ZONE
The time to insert a record is determined by the following factors, where the numbers indicate approximate proportions:
Connecting: (3)
Sending query to server: (2)
Parsing query: (2)
Inserting record: (1 x size of record)
Inserting indexes: (1 x number of indexes)
Closing: (1)
This does not take into consideration the initial overhead to open tables, which is done once for each concurrently running query.
The size of the table slows down the insertion of indexes by log N, assuming B-tree indexes.
You can use the following methods to speed up inserts:
If you are inserting many rows from the same client at the same time, use
INSERT statements with multiple VALUES lists to insert several
rows at a time. This is much faster (many times faster in some cases) than
using separate single-row INSERT statements. If you are adding data
to a non-empty table, you may tune the bulk_insert_buffer_size
variable to make it even faster.
See Section 5.2.3, “Server System Variables”.
If you are inserting a lot of rows from different clients, you can get
higher speed by using the INSERT DELAYED statement. See Section 13.1.4, “INSERT Syntax”.
With MyISAM tables you can insert rows at the same time that
SELECT statements are running if there are no deleted rows in the
tables.
When loading a table from a text file, use LOAD DATA INFILE. This
is usually 20 times faster than using a lot of INSERT statements.
See Section 13.1.5, “LOAD DATA INFILE Syntax”.
With some extra work, it is possible to make LOAD DATA INFILE run even
faster when the table has many indexes. Use the following procedure:
Optionally create the table with CREATE TABLE.
Execute a FLUSH TABLES statement or a mysqladmin flush-tables
command.
Use myisamchk --keys-used=0 -rq /path/to/db/tbl_name. This
removes all use of indexes for the table.
Insert data into the table with LOAD DATA INFILE. This does not
update any indexes and therefore is very fast.
If you are going to only read the table in the future, use myisampack to make it smaller. See Section 14.1.3.3, “Compressed Table Characteristics”.
Re-create the indexes with myisamchk -r -q /path/to/db/tbl_name. This creates the index tree in memory before
writing it to disk, which is much faster because it avoids lots of disk
seeks. The resulting index tree is also perfectly balanced.
Execute a FLUSH TABLES statement or a mysqladmin flush-tables
command.
Note that LOAD DATA INFILE also performs the preceding optimization
if you insert into an empty MyISAM table; the main difference is that you can let
myisamchk allocate much more temporary memory for the index creation
than you might want the server to allocate for index re-creation when it
executes the LOAD DATA INFILE statement.
As of MySQL 4.0, you can also use
ALTER TABLE instead of
myisamchk --keys-used=0 -rq tbl_name DISABLE KEYS/path/to/db/tbl_name and
ALTER TABLE instead of
myisamchk -r -q tbl_name ENABLE KEYS/path/to/db/tbl_name. This way you can also skip the
FLUSH TABLES steps.
You can speed up INSERT operations that are done
with multiple statements by locking your tables:
LOCK TABLES a WRITE; INSERT INTO a VALUES (1,23),(2,34),(4,33); INSERT INTO a VALUES (8,26),(6,29); UNLOCK TABLES;
A performance benefit occurs because the index buffer is flushed to disk only
once, after all INSERT statements have completed. Normally there would
be as many index buffer flushes as there are different INSERT
statements. Explicit locking statements are not needed if you can insert
all rows with a single statement.
For transactional tables, you should use BEGIN/COMMIT instead of
LOCK TABLES to get a speedup.
Locking also lowers the total time of multiple-connection tests, although the maximum wait time for individual connections might go up because they wait for locks. For example:
Connection 1 does 1000 inserts Connections 2, 3, and 4 do 1 insert Connection 5 does 1000 inserts
If you don't use locking, connections 2, 3, and 4 finish before 1 and 5. If you use locking, connections 2, 3, and 4 probably do not finish before 1 or 5, but the total time should be about 40% faster.
INSERT, UPDATE, and DELETE operations are very
fast in MySQL, but you can obtain better overall performance by
adding locks around everything that does more than about five inserts or
updates in a row. If you do very many inserts in a row, you could do a
LOCK TABLES followed by an UNLOCK TABLES once in a while
(about each 1,000 rows) to allow other threads access to the table. This
would still result in a nice performance gain.
INSERT is still much slower for loading data than LOAD DATA INFILE, even when using the strategies just outlined.
To get some more speed for MyISAM tables, for both LOAD DATA INFILE and INSERT, enlarge the key cache by increasing the
key_buffer_size system variable.
See Section 7.5.2, “Tuning Server Parameters”.
© 1995-2005 MySQL AB. All rights reserved.

User Comments
"If you are inserting a lot of rows from different clients, you can get higher speed by using the INSERT DELAYED statement."
I am running an application which inserts 20 to 120 rows per second on a single table (Format: Fixed/Row size: 46/No free data) using 5 to 10 client threads. I was using INSERT DELAYED but the delayed insert thread was consuming a lot of CPU and every 5 seconds all the insert threads would go into "waiting for handler lock" status for about 600 ms. The application also runs also selects and updates in the following proportion:
INSERT: 28%
SELECT: 28%
UPDATE: 44%
During that 600ms every 5 seconds, mysql didn't output anything to any thread (I checked it by monitoring network traffic).
Today I changed the INSERT DELAYED to a simple INSERT and CPU usage went down by 70% and no more intermitent locks are experienced.
Platform: Dual Intel Pentium III - Linux 2.4.20-13.7smp - MySQL 4.0.12-standard. Queries per second avg: 482.485
The suggestion of wrapping in transactions if you make more than about 5 modifications is in my experience a bit high.
I've seen massive performance increases in just wrapping 3 inserts. I imagine the performance gain is whenever you make more than a single insertion.
Add your own comment.