Details
-
New Feature
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
None
-
None
Description
Insert with unique constraints loop looks as follows:
for each entry in insertion_source
|
do
|
call before triggers
|
fetch u_entry from every unique index
|
if any u_entry is not empty, handle unique violation
|
insert entry (perhaps modified)
|
call after triggers (also logging etc)
|
end
|
For remote storages, the cost of query (both latency and throughput) is massively dominated by the total cost of RPC round-trips.
Here in this scheme, a number of round-trips is a number of entries x2 (unique check fetch + insert RPC).
We can practically postpone the real inserts later and batch them, but then the cost is still ~ number of entries.
We can optimize the process by batch-forward-prefetching entries to insert, dividing the cost by the size of batch (practically expected to be 100-1000).
The new process will look like:
batch_size = determine_batch_size(insertion_source)
|
for each [entry, batch, first_in_batch] in split_by_batches(insertion_source, batch_size)
|
do
|
if first_in_batch, call table->file->batch_prefetch(batch)
|
|
... // everything the old loop had
|
 |
end
|
Keep in mind that remote prefetch also locks the records internally against parallel overwrites.
Notes about applicability:
1. Some insertion_source's may not support batching, if forward-prefetching from them may have side-effects. In this case, determine_batch_size detects it and returns 1.
2. Before triggers may change the inserted record, which can emit a cache miss. This is known, and is out of scope of this ticket. This can be improved by feeding the before triggers to an optimizer and pre-fixing the batches for some simple enough subclass of triggers.
Nicely enough, this scheme may also improve the InnoDB insert performance by a more efficient page preload. Another oprimization is to keep the preloaded cache out of shared LRU to prevent contention.