Chunking handles multi-column indexes poorly

Bug #1130498 reported by Jeremy Tillman
64
This bug affects 10 people
Affects Status Importance Assigned to Milestone
Percona Toolkit moved to https://jira.percona.com/projects/PT
Fix Released
Medium
Carlos Salguero
CentOS
New
Undecided
Unassigned

Bug Description

I have a (InnoDB) table , with around 10 Millions rows, that uses a multicolumn primary key (4 INTs). When adding a column using pt-online-schema-change with no --chunk-index specified, it tries to use the PrimaryKey Constraint.

This fails during the 1st chunk transfer because:

Error copying rows from [table] to [table]_new: Error copying rows at chunk 1 of [table] because MySQL used only 8 bytes of the PRIMARY index instead of 16. See the --[no]check-plan documentation for more information.

The query that is generated for chunking is as such (for the select portion):

SELECT blah, blah, blah FROM `[table]` FORCE INDEX(`PRIMARY`) WHERE ((`pk_1` > ?) OR (`pk_1` = ? AND `pk_2` > ?) OR (`pk_1` = ? AND `pk_2` = ? AND `pk_3` > ?) OR (`pk_1` = ? AND `pk_2` = ? AND `pk_3` = ? AND `pk_4` >= ?)) AND ((`pk_1` < ?) OR (`pk_1` = ? AND `pk_2` < ?) OR (`pk_1` = ? AND `pk_2` = ? AND `pk_3` < ?) OR (`pk_1` = ? AND `pk_2` = ? AND `pk_3` = ? AND `pk_4` <= ?)) LOCK IN SHARE MODE /*pt-online-schema-change 20683 copy nibble*/

When give the --no-check-plan option is used to continue past this but starts soon receive a message as such:

Rows are copying very slowly. --chunk-size has been automatically reduced to 1. Check that the server is not being overloaded, or increase --chunk-time. The last chunk selected 1 rows and took 33.835 seconds to execute.

When using an index with a single column, the tool operates quickly (30 mins) on the same table.

I would suggest a fix of not trying retrieve the full chunk size every time but reduce WHERE clause to only have equality condition up to the inner most column of the index. (pk_1 = ? AND pk_2 = ? AND pk_3 = ? AND pk_4 >= ?)

Of course this wouldn't guarantee the chunk of each write be the chunk size but it would guarantee fast queries and the index being used to its max length ever time.

description: updated
tags: added: chunking pt-online-schema-change pt-table-checksum
summary: - pt-online-schema-change queries render tool unusable when multicolumn
- key is used
+ Chunking handles multi-column indexes poorly
Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

This affects pt-osc and ptc currently because these tools use the NibbleIterator module. I discovered this problem too awhile ago, but haven't gotten to fixing it because it's a weird and complex problem, and nibbling/chunking is not easy to change in the tools.

Three things are happening: first, NibbleIterator does make sub-optimal WHERE clauses with multi-column indexes. With 3+ column indexes, the tool makes a WHERE clause with mostly superfluous predicates. Second, the MySQL query planner/optimizer should cancel out these superfluous parts, but instead they confuse MySQL and make it use only part of the index. Using part of the index is where the "MySQL used only 8 bytes of the PRIMARY index instead of 16" comes from. We added --[no]check-plan this to detect when this happen in the wild because--third thing--this doesn't happen all the time. Sometimes MySQL isn't confused, and sometimes it is. When it is and uses part of the index, the result is an index scan. That's not too bad unless the table is large (e.g. millions of rows), and then even an index scan become expensive; and that's why --no-check-plan results in "Rows are copying very slowly".

So yes, we need to fix NibbleIterator, but I don't see this happening for awhile. I would like it to happen for PT 3.0, tentatively schedule for this summer, because we plan to rewrite pt-table-sync to use NibbleIterator like pt-table-checksum.

So the only workaround is currently to use a simpler index, i.e. 1 or 2 columns.

Changed in percona-toolkit:
status: New → Triaged
Changed in percona-toolkit:
milestone: none → 3.0.1
importance: Undecided → High
Changed in percona-toolkit:
importance: High → Medium
Revision history for this message
Jeremy Tillman (jeremy-tillman) wrote :

I see that the importance of this issue has been reduced. Is there any information as to the current plans for this issue? Thanks

Revision history for this message
Michael Titus (miket-r) wrote :

We have some large tables with multi-column primary keys that we cannot use pt-online-schema-change on. It would be a big help to have this bug fixed. Thanks.

Revision history for this message
Adam DePue (adepue) wrote :

We have a large portion of our schema that prevents the usage of pt-online-schema-change because of this bug as well. It would be extremely handy to have this fixed.

tags: added: rdba
tags: removed: rdba
Revision history for this message
Mrten (bugzilla-ii) wrote :

I hit this with a 4-column primary key but was able to run pt-osc with --chunk-index-columns 2 successfully.

Revision history for this message
Timur Bakeyev (timur.bakeyev) wrote :

End of 2015, pt-osc 2.2.3, still the same issue... MySQL table with 228mln rows and 4 columns primary key.

Error copying rows at chunk 1 of [table] because MySQL used only 8 bytes of the PRIMARY index instead of 15

Any progress and estimations?

Revision history for this message
Jeremy Tillman (jeremy-tillman) wrote :

We've had this ticket opened for some time now. I understand how having greater than 2 column keys create a larger problem for the algorithm. Are we at a block in seeking solutions to solve this issue or is it just getting any attention?

Revision history for this message
Daniël van Eeden (dveeden) wrote :

Maybe it could use mysql.innodb_index_stats to find a suitable column to use or suggest for --chunk-index=<some_index>

Revision history for this message
Dave Gregg (dgregg) wrote :

This issue still exists is 2.2.16 !!!!!!!!

Revision history for this message
Carlos Salguero (carlos-salguero) wrote :

This has been fixed in 2.2.19 as a consequence of https://bugs.launchpad.net/percona-toolkit/+bug/1613915

My steps to test today:

1) Created a table and populated it using this script: https://gist.github.com/percona-csalguero/3dcfbd517953bc002f869654e4434ece
2) After running the program we have:

mysql -e 'show create table test.t1\G'
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `pk1` int(11) NOT NULL,
  `pk2` int(11) NOT NULL,
  `pk3` int(11) NOT NULL,
  `pk4` int(11) NOT NULL,
  `f1` timestamp NULL DEFAULT NULL,
  `f2` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`pk1`,`pk2`,`pk3`,`pk4`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

mysql -e 'select count(*) from test.t1\G'
*************************** 1. row ***************************
count(*): 10000000

3) Run pt-osc: bin/pt-online-schema-change --alter "ADD COLUMN c1 INT" D=test,t=t1 --execute

No slaves found. See --recursion-method if host karl-HP-ENVY has slaves.
Not checking slave lag because no slaves were found and --check-slave-lag was not specified.
Operation, tries, wait:
  analyze_table, 10, 1
  copy_rows, 10, 0.25
  create_triggers, 10, 1
  drop_triggers, 10, 1
  swap_tables, 10, 1
  update_foreign_keys, 10, 1
Altering `test`.`t1`...
Creating new table...
Created new table test._t1_new OK.
Altering new table...
Altered `test`.`_t1_new` OK.
2016-10-04T16:44:09 Creating triggers...
2016-10-04T16:44:09 Created triggers OK.
2016-10-04T16:44:09 Copying approximately 8596422 rows...
Copying `test`.`t1`: 63% 00:17 remain
2016-10-04T16:45:04 Copied rows OK.
2016-10-04T16:45:04 Analyzing new table...
2016-10-04T16:45:04 Swapping tables...
2016-10-04T16:45:04 Swapped original and new tables OK.
2016-10-04T16:45:04 Dropping old table...
2016-10-04T16:45:04 Dropped old table `test`.`_t1_old` OK.
2016-10-04T16:45:04 Dropping triggers...
2016-10-04T16:45:04 Dropped triggers OK.
Successfully altered `test`.`t1`.

4) Check
mysql -e 'show create table test.t1\G'
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `pk1` int(11) NOT NULL,
  `pk2` int(11) NOT NULL,
  `pk3` int(11) NOT NULL,
  `pk4` int(11) NOT NULL,
  `f1` timestamp NULL DEFAULT NULL,
  `f2` timestamp NULL DEFAULT NULL,
  `c1` int(11) DEFAULT NULL,
  PRIMARY KEY (`pk1`,`pk2`,`pk3`,`pk4`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

mysql -e 'select count(*) from test.t1\G'
*************************** 1. row ***************************
count(*): 10000000

Changed in percona-toolkit:
assignee: nobody → Carlos Salguero (carlos-salguero)
Changed in percona-toolkit:
status: Triaged → Fix Released
Revision history for this message
zeroton (zeroton) wrote :

i still see error below when i use pt-table-checksum version 3.0.4
pt-tool:3.0.4
system:Red Hat Enterprise Linux Server release 6.8
mysql:5.6.11
command:
pt-table-checksum --host --user --password --replicate=test.checksums --empty-replicate-table --create-replicate-table --empty-replicate-table --create-replicate-table --no-check-binlog-format --chunk-size-limit=10.0 --recursion-method=none --tables=a.b
08-11T10:05:36 Skipping chunk 1 of a.b because MySQL used only 52 bytes of the PRIMARY index instead of 172. See the --[no]check-plan documentation for more information.
            TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
08-11T10:06:46 0 0 0 1459 1459 69.588 a.b

Skipping chunk 1 of a.b because MySQL used only 52 bytes of the PRIMARY index instead of 172. See the --[no]check-plan documentation for more information.

and i did not find the release log where this bug is fixed

Revision history for this message
Shahriyar Rzayev (rzayev-sehriyar) wrote :

Percona now uses JIRA for bug reports so this bug report is migrated to: https://jira.percona.com/browse/PT-604

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.