pt-archiver with Auto-Increment ColumnAs a best practice before dropping a large table in MySQL, pt-archiver can be used to delete all the records in batches. This helps to avoid a situation where your server may get stalled under certain circumstances.

I recently read a comment from a user saying “The pt-archiver is not working as expected! It is skipping the last record, which seems like a bug.”. Let’s examine pt-archiver’s default behavior and understand why the author of this comment believes that pt-archiver is bugged (Spoiler: It’s not!).

But wait, before continuing on busting the blame, let me clarify why to use pt-archiver before dropping large tables.

When we drop a table in MySQL:

  • Table data/index (ibd) and definition (frm) files are removed.
  • Triggers are removed.
  • Table definition cache is updated by removing the table being dropped.
  • InnoDB buffer pool is scanned for associated pages to invalidate them.

Note that DROP is a DDL statement and it will require a Metadata Lock (MDL) to complete the task causing all the other threads to wait on that. This also creates additional pressure on the buffer pool for purging a large number of data pages associated with the table being dropped.

And finally, the table_definition_cache operation requires LOCK_open mutex to clean up and this causes all other threads to wait until the drop is complete.

To reduce the severity of this operation we can use pt-archiver to delete large data in small chunks, thus lowering the table size significantly. Once we have deleted records from the large table, the drop operation goes fast without creating a performance impact.

Coming back to debunking the blame. This behavior was noted by a community member that after the pt-archiver was completed, the table still had one row pending.

Generating a lab the scenarios proved that these allegations appear to be true:

The same happens when we use pt-archiver for data copy with –no-delete. Our tool, pt-archiver, appears not to copy the max value to the destination table.

We have a bug report that was already in place https://jira.percona.com/browse/PT-837 noting this behavior. But is this really a bug?

Reading through the pt-archiver documentation, there’s an option –[no]safe-auto-increment which describes the usage: “Do not archive rows with max AUTO_INCREMENT.” 

Meaning, the option –safe-auto-increment (default) adds an extra WHERE clause to prevent pt-archiver from removing the newest row when ascending a single-column AUTO_INCREMENT as seen in the code section below:

 

Let’s see the difference between the two commands via dry-run output:

Did you note the additional clause “AND (id < ‘5009’)” above?

This option of –no-safe-auto-increment guards against re-using AUTO_INCREMENT values if the server restarts. Note that the extra WHERE clause contains the maximum value of the auto-increment column as of the beginning of the archive or purge job. If new rows are inserted while pt-archiver is running, pt-archiver will not see them.

Alright, now we know the “why” of the “blame”, but why? What is the issue around safety for AUTO_INCREMENT?

The AUTO_INCREMENT counter is stored in memory and as MySQL restarts (crashes or otherwise), the counter will reset to the max value. If this happens and the table is accepting writes, the AUTO_INCREMENT value will change.

These observations convincingly tell us that the problem here was not really with pt-archiver but with the option chosen. It is important to understand the use –no-safe-auto-increment option, in the case of using pt-archiver while working on AUTO_INCREMENT columns.

Let’s just verify it with our lab data.

The same goes for a copy operation with –no-delete option.

 

Now that we have established the understanding of pt-archiver’s –[no]safe-auto-increment option and before we conclude that everything is well and good; let us give the option itself some more thought.

  1. The –no-delete operation should by default include –no-safe-auto-increment option.
    • At present, safe-auto-increment is default behavior. When we use –no-delete option of pt-archiver, there are no delete operations. This means safe-auto-increment should not be a reason for concern.
    • Do you agree? Do you want to counter? Use comments.
  2. For MySQL 8.0, safe-auto-increment option is not required.
    • This thought comes from the knowledge that from MySQL 8.0 onwards, the auto-increment values are persistent and survives restarts or crashes. –Ref: MySQL worklog
    • And since MySQL 8.0 auto-increment is persisted via redo logs, this makes them a reason for not being a concern for our beloved pt-archiver. Thus we don’t need a safe-auto-increment option at all.
    • Do you agree? Do you want to counter?

Well, point #2 was too convincing until it was refuted by my friend Ananias with the following facts.

  • Reuse of previously allocated auto-increment counters cannot be guaranteed.

However, in the case of an unexpected server exit, reuse of a previously allocated auto-increment value cannot be guaranteed. Each time the current maximum auto-increment value is changed due to an INSERT or UPDATE operation, the new value is written to the redo log, but if the unexpected exit occurs before the redo log is flushed to disk, the previously allocated value could be reused when the auto-increment counter is initialized after the server is restarted” – MySQL Documentation

  • Yet another fact, as documentation reads “As of MySQL 8.0.21, you can disable redo logging”. Though this feature is specifically created for speeding up the data load to MySQL and is not to be used in production; “To err is human”.
  • That makes the “safe-auto-increment” option to stay in 8.0+. The only option we are left with is to understand the options.

Conclusion

The pt-archiver is a great tool for archiving MySQL data and it is important to be aware of all the options to have full control of what we want to achieve using it.

It’d be interesting to know if you have any thoughts while reading this; please use comments and share.

Subscribe
Notify of
guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
John Russell

My preferred behavior in this case would be (a) don’t delete the row with the max auto-increment value from the original table, (b) but do copy it to the other table anyway. That way, if you recreated the original table using the data from the archive table, you’d have all the data. If you kept using the original table, the auto-increment value would keep ascending. And if you copied more data from that same table to the archive table in the future, you would just get 1 row rejected due to a duplicate key.

Aurélien LEQUOY

I am the author of mentioned topic :p, I will try again with newest version =)

Aurélien LEQUOY

For me, I would to get all rows matching my query, that’s why my confusion =), Thanks Kedar, for this explanation ! When I made this test I should try to keep some data, but it’s was more simple to check that all tables were empties.