Skip to content

Commit c3335fd

Browse files
committed
PS-10995 [DOCS] -[feedback] PS 8.4 Innodb index creation
modified: docs/innodb-expanded-fast-index-creation.md
1 parent 8b2072e commit c3335fd

3 files changed

Lines changed: 222 additions & 35 deletions

File tree

6.59 MB
Loading

docs/extended-mysqldump.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ More information can be found in [Backup Locks](backup-locks.md).
1717
More information can be found in
1818
[Compressed columns with dictionaries](compressed-columns.md).
1919

20+
## `InnoDB` secondary keys and `--innodb-optimize-keys`
21+
22+
For *InnoDB* tables, `--innodb-optimize-keys` omits secondary keys (and related
23+
constraints) from the initial `CREATE TABLE` in the dump and adds them in a
24+
follow-up `ALTER TABLE` after the data is loaded. That pattern works well when
25+
the target server can build those indexes using [expanded fast index
26+
creation](innodb-expanded-fast-index-creation.md). See that page for
27+
limitations (foreign keys, partitioned tables, `AUTO_INCREMENT`, implicit
28+
primary keys, and others) and for the `expand_fast_index_creation` variable.
29+
2030
## Taking backup by descending primary key order
2131

2232
–order-by-primary-desc tells `mysqldump` to take the backup by
Lines changed: 212 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,150 @@
11
# Expanded fast index creation
22

3-
Percona has implemented several changes related to *MySQL*’s fast index creation
4-
feature. Fast index creation was implemented in *MySQL* as a way to speed up the
5-
process of adding or dropping indexes on tables with many rows.
3+
## What fast index creation is
64

7-
This feature implements a session variable that enables extended fast index
8-
creation. Besides optimizing DDL directly,
9-
[expand_fast_index_creation](#expanded-fast-index-creation) may also optimize index access for
10-
subsequent DML statements because using it results in much less fragmented
11-
indexes.
5+
In *InnoDB*, secondary indexes are separate B-tree structures from the clustered
6+
index (the primary key). When the server creates a new secondary index on
7+
an existing table, the server can use two conceptually different approaches:
128

13-
## The **mysqldump** command
9+
1. Row-by-row maintenance — For each row, insert that row’s entries into the
10+
new secondary index as you go. Those inserts arrive in primary-key order, not
11+
in secondary-key order, so the growing B-tree suffers many random-looking
12+
page splits and a large amount of write amplification. If the server is
13+
also copying the table (rebuild `ALTER TABLE`), the same pattern applies:
14+
every row copied into the new table must update every secondary index
15+
immediately.
1416

15-
A new option, `--innodb-optimize-keys`, was implemented in **mysqldump**. It
16-
changes the way *InnoDB* tables are dumped, so that secondary and foreign keys
17+
18+
2. Fast index creation (sorted / bulk build) — The server scans the table’s
19+
clustered index in primary-key order, generates secondary-key tuples, sorts
20+
them (often using external merge sort), and builds the secondary index from
21+
that ordered stream. Work is staged in temporary files under the configured
22+
`tmpdir`, then merged into a compact B-tree. That path avoids the worst
23+
random-insert behavior of the row-by-row approach and usually completes with
24+
less I/O and a less fragmented index.
25+
26+
So fast index creation means: build the secondary index from a sorted
27+
stream after reading the table (or a copy) in clustered index order, instead of
28+
growing the index by arbitrary-order inserts during the same phase as the data
29+
copy.
30+
31+
Dropping an index is already a cheap metadata change in many cases; the
32+
performance win is dominated by creating indexes on large tables.
33+
34+
## How expanded fast index creation differs from Oracle MySQL {{vers}}
35+
36+
The figure below contrasts a typical Oracle MySQL workflow with Percona Server
37+
when expanded fast index creation is in use (including
38+
`mysqldump --innodb-optimize-keys` during restore).
39+
40+
![Comparison of standard MySQL and Percona Server with expanded fast index creation for backup restore and copy-style ALTER TABLE or OPTIMIZE TABLE](_static/expand-fast-creation.png)
41+
42+
The following compares Percona Server for MySQL with Oracle MySQL {{vers}} on
43+
code paths that still rebuild the table. InnoDB classifies each `ALTER TABLE`
44+
operation by algorithm (`INSTANT`, `INPLACE`, `COPY`, and so on); those
45+
classifications can change between releases, so treat the [InnoDB online DDL
46+
documentation :octicons-link-external-16:](https://dev.mysql.com/doc/refman/{{vers}}/en/innodb-online-ddl.html)
47+
as authoritative for whether a specific statement performs a copy in your
48+
version.
49+
50+
Upstream *MySQL* (*InnoDB*) already uses a sorted, bulk-style path when MySQL
51+
adds a secondary index in operations that are implemented as “add index
52+
only” (for example, some `CREATE INDEX` / `ALTER TABLE ... ADD INDEX` flows
53+
that do not rebuild the whole table).
54+
55+
Where Oracle MySQL still does a full table rebuild (copy algorithm —
56+
for example many `ALTER TABLE` changes that force a new table), rows are
57+
inserted into the new copy while all secondary indexes are live. Each
58+
insert must update every non-primary index at once. Even if the server later
59+
uses efficient mechanics for individual index builds, interleaving those
60+
updates with the copy keeps more indexes “hot” for the whole copy and tends to
61+
produce heavier random I/O and more fragmented trees than deferring secondary
62+
index creation until the clustered data is complete.
63+
64+
Percona Server for MySQL extends that behavior with expanded fast index
65+
creation (controlled by
66+
[`expand_fast_index_creation`](#expanded-fast-index-creation)): on rebuild-style
67+
`ALTER TABLE` / `OPTIMIZE TABLE`, eligible non-unique secondary indexes are
68+
dropped for the copy phase and recreated afterward using the fast sorted-build
69+
path on the finished table. The copy phase then maintains only what *InnoDB*
70+
requires for the clustered index (and any indexes that cannot be deferred),
71+
which is the main difference from Oracle MySQL on the same code paths.
72+
73+
Oracle MySQL {{vers}} can apply `INSTANT` or in-place (`INPLACE`)
74+
DDL to many `ALTER TABLE` operations so the server avoids a full table copy or
75+
keeps work inside the existing *InnoDB* file. That path is separate from the
76+
rebuild logic `expand_fast_index_creation` augments; there is no interaction to
77+
“tune” for those statements.
78+
79+
## When the expanded fast index creation optimization applies
80+
81+
### `INSTANT`, `INPLACE`, and why the `expand_fast_index_creation` variable usually does not matter for those algorithms
82+
83+
If an `ALTER TABLE` runs as `INSTANT` (for example, adding a nullable column at
84+
the end of the table when supported) or as an online in-place operation that
85+
does not rebuild the whole table, the server is not performing a full table
86+
copy that Percona optimizes. In those cases
87+
`expand_fast_index_creation` is generally unnecessary: the expensive secondary
88+
index pattern that expanded fast index creation improves simply is not used in the same way.
89+
90+
### When `expand_fast_index_creation` helps
91+
92+
`expand_fast_index_creation` is most beneficial when the operation requires a
93+
table copy—for example changing a column’s data type in a way that forces a
94+
rebuild, or other alters classified with the copy algorithm. On that path,
95+
Percona Server intercepts the copy so eligible non-unique secondary indexes are
96+
rebuilt with the sorted temporary-file workflow instead of being maintained on
97+
every inserted row during the copy.
98+
99+
Expanded fast index creation only affects statements that rebuild the table and
100+
copy rows into a new *InnoDB* table. Typical cases include:
101+
102+
* `OPTIMIZE TABLE` on an *InnoDB* table (internally `ALTER TABLE ... ENGINE=InnoDB`)
103+
104+
* `ALTER TABLE` operations that the server implements with a table rebuild and
105+
the copy algorithm, as listed in the [InnoDB online DDL operations
106+
table :octicons-link-external-16:](https://dev.mysql.com/doc/refman/{{vers}}/en/innodb-online-ddl-operations.html)
107+
108+
* An `ALTER TABLE` where you explicitly request `ALGORITHM=COPY` (when that
109+
algorithm is permitted for the operation)
110+
111+
Routine schema changes that stay on `INSTANT` or `INPLACE` never enter the
112+
table-copy rebuild path and are unaffected by `expand_fast_index_creation`.
113+
114+
## Verify and monitor
115+
116+
* Check whether expanded fast index creation is enabled:
117+
118+
```sql
119+
SHOW VARIABLES LIKE 'expand_fast_index_creation';
120+
```
121+
122+
In Percona Server for MySQL {{vers}} the default is `OFF`. Enable
123+
`expand_fast_index_creation` for a
124+
session or globally before running DDL, for example
125+
`SET SESSION expand_fast_index_creation = ON;`.
126+
127+
128+
* To see how *MySQL* classifies a specific `ALTER TABLE`, use the online DDL
129+
documentation for your version (linked [above](#when-the-expanded-fast-index-creation-optimization-applies)).
130+
There is no single `EXPLAIN` for DDL; classification is per operation and
131+
version.
132+
133+
134+
* [`tmpdir`](https://dev.mysql.com/doc/refman/{{vers}}/en/server-system-variables.html#sysvar_tmpdir)
135+
free space is the usual operational bottleneck; see
136+
[Limitations](#limitations) for how large `tmpdir` must be and what happens when
137+
`tmpdir` space is exhausted.
138+
139+
Besides shortening DDL directly,
140+
[`expand_fast_index_creation`](#expanded-fast-index-creation) may also help
141+
subsequent DML because indexes built in one sorted pass are often less
142+
fragmented than those maintained incrementally through a long copy.
143+
144+
## The mysqldump command
145+
146+
The `--innodb-optimize-keys` option changes the way *InnoDB* tables are dumped,
147+
so that secondary and foreign keys
17148
are created after loading the data, thus taking advantage of fast index
18149
creation. More specifically:
19150

@@ -25,55 +156,85 @@ create the previously omitted keys.
25156

26157
## `ALTER TABLE`
27158

28-
When `ALTER TABLE` requires a table copy, secondary keys are now dropped and
159+
When `ALTER TABLE` requires a table copy, secondary keys are dropped and
29160
recreated later, after copying the data. The following restrictions apply:
30161

31-
* Only non-unique keys can be involved in this optimization.
162+
* Only non-unique keys can be involved in the expanded fast index creation optimization.
32163

33164
* If the table contains foreign keys, or a foreign key is being added as a part
34-
of the current `ALTER TABLE` statement, the optimization is disabled for all
165+
of the current `ALTER TABLE` statement, the expanded fast index creation optimization is disabled for all
35166
keys.
36167

37-
* If the table is partitioned, the optimization is disabled for all keys.
168+
* If the table is partitioned, the expanded fast index creation optimization is disabled for all keys.
38169

39170
## `OPTIMIZE TABLE`
40171

41172
Internally, `OPTIMIZE TABLE` is mapped to `ALTER TABLE ... ENGINE=innodb`
42-
for *InnoDB* tables. As a consequence, it now also benefits from fast index
43-
creation, with the same restrictions as for `ALTER TABLE`.
173+
for *InnoDB* tables. As a consequence, `OPTIMIZE TABLE` also benefits from fast index
174+
creation when `expand_fast_index_creation` is enabled and the expanded fast index creation optimization
175+
applies, with the same restrictions as for `ALTER TABLE`.
176+
177+
## Limitations
178+
179+
!!! warning "`tmpdir` free space — the most common failure"
180+
181+
In practice, the usual reason expanded fast index creation fails is
182+
running out of disk space on the filesystem used for
183+
[`tmpdir`](https://dev.mysql.com/doc/refman/{{vers}}/en/server-system-variables.html#sysvar_tmpdir)
184+
(often the same mount as `/tmp`).
185+
186+
With expanded fast index creation enabled, the server does not only make index
187+
maintenance cheaper in memory: the server materializes each secondary index in
188+
temporary files (sorted runs and merge passes) and only then merges the
189+
result into the final *InnoDB* index. That can consume far more transient
190+
space than a rough “indexes fit in the tablespace” estimate suggests.
44191

45-
## Caveats
192+
Size the filesystem using the secondary index footprint you are
193+
rebuilding, not the primary table size alone. You typically need
194+
well above the on-disk size of those secondary indexes as free
195+
space under `tmpdir`, on top of anything else the same `ALTER TABLE` or
196+
`OPTIMIZE TABLE` already needs. For example, a table with about 500 GB
197+
of data and about 200 GB of secondary indexes may still require
198+
significantly more than 200 GB of free `tmpdir` space while those
199+
indexes are being built.
46200

47-
*InnoDB* fast index creation uses temporary files in tmpdir for all indexes
48-
being created. So make sure you have enough tmpdir space when using
49-
[expand_fast_index_creation](#expanded-fast-index-creation). It is a session variable, so you can
50-
temporarily switch it off if you are short on tmpdir space and/or don’t want
51-
this optimization to be used for a specific table.
201+
If `tmpdir` fills during the operation, the statement fails and rolls
202+
back. You lose the work done up to the failure and must free or enlarge
203+
storage (or point `tmpdir` at a larger volume), or run with
204+
`expand_fast_index_creation` disabled for that job, before retrying.
52205

53-
There’s also a number of cases when this optimization is not applicable:
206+
[`expand_fast_index_creation`](#expanded-fast-index-creation) is a session or
207+
global variable: you can set `expand_fast_index_creation` to `OFF` for a single session if `tmpdir` is
208+
too small for a specific table or maintenance window.
209+
210+
There’s also a number of cases when the expanded fast index creation optimization is not applicable:
54211

55212
* `UNIQUE` indexes in `ALTER TABLE` are ignored to enforce uniqueness where
56213
necessary when copying the data to a temporary table;
57214

215+
58216
* `ALTER TABLE` and `OPTIMIZE TABLE` always process tables containing
59217
foreign keys as if [expand_fast_index_creation](#expanded-fast-index-creation) is OFF to avoid
60218
dropping keys that are part of a FOREIGN KEY constraint;
61219

220+
62221
* `ALTER TABLE` and `OPTIMIZE TABLE` always process partitioned tables as if
63222
[expand_fast_index_creation](#expanded-fast-index-creation) is OFF;
64223

65-
* **mysqldump --innodb-optimize-keys** ignores foreign keys because
66-
*InnoDB* requires a full table rebuild on foreign key changes. So adding them
224+
225+
* mysqldump --innodb-optimize-keys ignores foreign keys because
226+
*InnoDB* requires a full table rebuild on foreign key changes. So adding foreign keys
67227
back with a separate `ALTER TABLE` after restoring the data from a dump
68228
would actually make the restore slower;
69229

70-
* **mysqldump --innodb-optimize-keys** ignores indexes on
71-
`AUTO_INCREMENT` columns, because they must be indexed, so it is impossible
72-
to temporarily drop the corresponding index;
73230

74-
* **mysqldump --innodb-optimize-keys** ignores the first UNIQUE index on
231+
* mysqldump --innodb-optimize-keys ignores indexes on
232+
`AUTO_INCREMENT` columns, because those columns must be indexed, so temporarily dropping the corresponding index is impossible;
233+
234+
235+
* mysqldump --innodb-optimize-keys ignores the first UNIQUE index on
75236
non-nullable columns when the table has no `PRIMARY KEY` defined, because in
76-
this case *InnoDB* picks such an index as the clustered one.
237+
that layout *InnoDB* picks such an index as the clustered one.
77238

78239
## System variables
79240

@@ -86,12 +247,28 @@ this case *InnoDB* picks such an index as the clustered one.
86247
| Scope: | Local/Global |
87248
| Dynamic: | Yes |
88249
| Data type | Boolean |
89-
| Default value | ON/OFF |
250+
| Default value | OFF |
251+
252+
When set to `ON`, *InnoDB* may drop eligible non-unique secondary indexes for the
253+
data-copy phase of rebuild-style `ALTER TABLE` and `OPTIMIZE TABLE`, then
254+
recreate those indexes with the sorted bulk build described [above](#what-fast-index-creation-is).
255+
256+
## Related documentation
257+
258+
### Percona Server for MySQL documentation
259+
260+
* [Percona Server for MySQL feature comparison](feature-comparison.md) — how expanded fast index creation compares to MySQL {{vers}}
261+
262+
* [Percona Server for MySQL variables](percona-server-system-variables.md) — full list of Percona-specific system variables, including `expand_fast_index_creation`
263+
264+
* [Extended mysqldump](extended-mysqldump.md) — Percona `mysqldump` enhancements, including `--innodb-optimize-keys`
90265

91-
!!! admonition "See also"
266+
* [InnoDB page fragmentation counters](innodb-fragmentation-count.md) — monitoring index fragmentation
92267

93-
[Improved InnoDB fast index creation :octicons-link-external-16:](https://www.mysqlperformanceblog.com/2011/11/06/improved-innodb-fast-index-creation/)
268+
### MySQL Reference Manual
94269

95-
[Thinking about running OPTIMIZE on your InnoDB Table? Stop! :octicons-link-external-16:](https://www.mysqlperformanceblog.com/2010/12/09/thinking-about-running-optimize-on-your-innodb-table-stop/)
270+
* [InnoDB and online DDL :octicons-link-external-16:](https://dev.mysql.com/doc/refman/{{vers}}/en/innodb-online-ddl.html)
96271

272+
* [InnoDB online DDL operations :octicons-link-external-16:](https://dev.mysql.com/doc/refman/{{vers}}/en/innodb-online-ddl-operations.html)
97273

274+
* [`tmpdir` system variable :octicons-link-external-16:](https://dev.mysql.com/doc/refman/{{vers}}/en/server-system-variables.html#sysvar_tmpdir)

0 commit comments

Comments
 (0)