PT-TABLE-SYNC(1)
๐ NAME ๐
pt-table-sync โ bestie, this is the tool that synchronizes MySQL table data efficiently. It's from the User Contributed Perl Documentation, and it's lowkey iconic.
โจ SYNOPSIS โจ
Usage: pt-table-sync [OPTIONS] DSN [DSN]
pt-table-sync synchronizes data efficiently between MySQL tables. That's the whole vibe.
โ ๏ธ okay so listen โ this tool changes data, so for maximum safety you should back up your data before using it. No cap. ๐ซถ
When you're synchronizing a server that's a replication replica using the --replicate or --sync-to-source methods, it always makes the changes on the replication source, never the replication replica directly. That's, like, generally the only safe way to bring a replica back in sync with its source โ because changes made to the replica are usually the source of the problems in the first place, iykyk. However! The changes it makes on the source should be no-op changes that set the data to their current values, and actually affect only the replica. ๐
Sync db.tbl on host1 to host2:
pt-table-sync --execute h=host1,D=db,t=tbl h=host2
Sync all tables on host1 to host2 and host3:
pt-table-sync --execute host1 host2 host3
Make replica1 have the same data as its replication source:
pt-table-sync --execute --sync-to-source replica1
Resolve differences that pt-table-checksum found on all replicas of source1:
pt-table-sync --execute --replicate percona.checksum source1
Same as above but only resolve differences on replica1:
pt-table-sync --execute --replicate percona.checksum \
--sync-to-source replica1
Sync source2 in a source-source replication configuration, where source2's copy of db.tbl is known or suspected to be incorrect:
pt-table-sync --execute --sync-to-source h=source2,D=db,t=tbl
๐ Note that in the source-source configuration, the following will NOT do what you want, because it will make changes directly on source2, which will then flow through replication and change source1's data:
# Don't do this in a source-source setup!
pt-table-sync --execute h=source1,D=db,t=tbl source2
๐ฅ RISKS ๐ฅ
WARNING: pt-table-sync changes data! Before using this tool, please do all of these, fr fr:
- Read the tool's documentation ๐
- Review the tool's known
BUGS๐ - Test the tool on a non-production server ๐งช
- Backup your production server and verify the backups ๐พ
pt-table-sync is mature, proven in the real world, and well tested โ but if used improperly it can have adverse consequences ๐ญ. Always test syncing first with --dry-run and --print.
๐ธ DESCRIPTION ๐ธ
pt-table-sync does one-way and bidirectional synchronization of table data. It does not synchronize table structures, indexes, or any other schema objects. What follows describes one-way synchronization โ BIDIRECTIONAL SYNCING is described later.
This tool is complex and functions in several different ways, so to use it safely and effectively you should understand three things: the purpose of --replicate, finding differences, and specifying hosts. These three concepts are closely related and determine how the tool will run. Here's the abbreviated logic, bestie:
if DSN has a t part, sync only that table:
if 1 DSN:
if --sync-to-source:
The DSN is a replica. Connect to its source and sync.
if more than 1 DSN:
The first DSN is the source. Sync each DSN in turn.
else if --replicate:
if --sync-to-source:
The DSN is a replica. Connect to its source, find records
of differences, and fix.
else:
The DSN is the source. Find replicas and connect to each,
find records of differences, and fix.
else:
if only 1 DSN and --sync-to-source:
The DSN is a replica. Connect to its source, find tables and
filter with --databases etc, and sync each table to the source.
else:
find tables, filtering with --databases etc, and sync each
DSN to the first.
So pt-table-sync can run in one of two ways: with --replicate, or without. The default is to run without --replicate, which causes pt-table-sync to automatically find differences efficiently with one of several algorithms (peep ALGORITHMS). Alternatively, the value of --replicate, if specified, causes pt-table-sync to use the differences already found by having previously ran pt-table-checksum with its own --replicate option.
Strictly speaking, you don't need to use --replicate because pt-table-sync can find differences on its own โ but many people use --replicate if, for example, they checksum regularly using pt-table-checksum then fix differences as needed with pt-table-sync. If you're unsure, read each tool's documentation carefully and decide for yourself, or consult with an expert ๐ง.
Regardless of whether --replicate is used or not, you need to specify which hosts to sync. There are two ways: with --sync-to-source, or without. Specifying --sync-to-source makes pt-table-sync expect one and only replica DSN on the command line. The tool will automatically discover the replica's source and sync it so that its data is the same as its source. This is accomplished by making changes on the source which then flow through replication and update the replica to resolve its differences. ๐
๐ Be careful though: although this option specifies and syncs a single replica, if there are other replicas on the same source, they will receive via replication the changes intended for the replica that you're trying to sync. Yeah. That's a whole thing.
Alternatively, if you do not specify --sync-to-source, the first DSN given on the command line is the source host. There is only ever one source host. If you don't also specify --replicate, then you must specify at least one other DSN as the destination host. There can be one or more destination hosts. Source and destination hosts must be independent โ they cannot be in the same replication topology. pt-table-sync will die with an error if it detects that a destination host is a replica, because changes are written directly to destination hosts (and it's not safe to write directly to replicas ๐). Or, if you specify --replicate (but not --sync-to-source), then pt-table-sync expects one and only one source DSN on the command line. The tool will automatically discover all the source's replicas and sync them to the source. This is the only way to sync several (all) replicas at once โ because --sync-to-source only specifies one replica. ๐
Each host on the command line is specified as a DSN. The first DSN (or only DSN for cases like --sync-to-source) provides default values for other DSNs, whether those other DSNs are specified on the command line or auto-discovered by the tool. So in this example:
pt-table-sync --execute h=host1,u=msandbox,p=msandbox h=host2
...the host2 DSN inherits the u and p DSN parts from the host1 DSN. Use the --explain-hosts option to see how pt-table-sync will interpret the DSNs given on the command line. ๐ฆ
๐ LIMITATIONS ๐
Replicas using row-based replication
pt-table-sync requires statement-based replication when used with the --sync-to-source or --replicate option. Therefore it will set binlog_format=STATEMENT on the source for its session if required. To do this, the user must have SUPER privilege. โจ
๐ OUTPUT ๐
If you specify the --verbose option, you'll see information about the differences between the tables. There is one row per table. Each server is printed separately. For example:
# Syncing h=host1,D=test,t=test1
# DELETE REPLACE INSERT UPDATE ALGORITHM START END EXIT DATABASE.TABLE
# 0 0 3 0 Chunk 13:00:00 13:00:17 2 test.test1
Table test.test1 on host1 required 3 INSERT statements to synchronize, and it used the Chunk algorithm (see ALGORITHMS). The sync operation for this table started at 13:00:00 and ended 17 seconds later (times taken from NOW() on the source host). And because differences were found, its EXIT STATUS was 2.
If you specify the --print option, you'll see the actual SQL statements that the script uses to synchronize the table โ if --execute is also specified.
If you want to see the SQL statements that pt-table-sync is using to select chunks, nibbles, rows, etc., then specify --print once and --verbose twice. ๐ Be careful though: this can print a lot of SQL statements. Like, a lot a lot.
There are cases where no combination of INSERT, UPDATE or DELETE statements can resolve differences without violating some unique key. For example, suppose there's a primary key on column a and a unique key on column b. Then there is no way to sync these two tables with straightforward UPDATE statements:
+---+---+ +---+---+
| a | b | | a | b |
+---+---+ +---+---+
| 1 | 2 | | 1 | 1 |
| 2 | 1 | | 2 | 2 |
+---+---+ +---+---+
The tool rewrites queries to DELETE and REPLACE in this case. This is automatically handled after the first index violation, so you don't have to worry about it. Slay. ๐
๐ Be careful when using pt-table-sync in any source-source setup. Source-source replication is inherently tricky, and it's easy to make mistakes. You need to be sure you're using the tool correctly for source-source replication. See the SYNOPSIS for the overview of the correct usage.
๐ธ Also be careful with tables that have foreign key constraints withON DELETEorON UPDATEdefinitions, because these might cause unintended changes on the child tables. See--[no]check-child-tables.
In general, this tool is best suited when your tables have a primary key or unique index. Although it can synchronize data in tables lacking a primary key or unique index, it might be best to synchronize that data by another means. ๐
๐ REPLICATION SAFETY ๐
okay so bestie, syncing a replication source and its replica safely is genuinely a non-trivial problem โ like, no cap. There's a whole pile of stuff to worry about: other processes out there changing data, someone trying to change data on the replica, whether your destination and source are actually a source-source pair, and so much more. ๐ญ
so the generally safe move is: change the data on the source, and let those changes flow through replication to the replica like any other change would. cute, right? but โ and this is the big but โ that only works if you can REPLACE into the table on the source. and REPLACE only works if there's a unique index on the table (otherwise it just acts like a plain old INSERT, which is not the vibe you want).
if your table does have unique keys, use the --sync-to-source and/or --replicate options to sync a replica to its source. that'll generally do the right thing. โจ but when there's no unique key on the table, there is literally no choice but to change the data on the replica โ and pt-table-sync will detect that you're trying to do that. it will complain and die unless you specify --no-check-replica (see --[no]check-replica). like, it's not being mean, it's being safe. ๐
if you're syncing a table without a primary or unique key on a source-source pair, you must change the data on the destination server. therefore you need to specify --no-bin-log for safety (see --[no]bin-log). if you don't? the changes you make on the destination server will replicate right back to the source server and change the data there. ๐ซ yeah. bad.
the generally safe thing to do on a source-source pair is to use the--sync-to-sourceoption so you don't change the data on the destination server at all. you'll also need--no-check-replicato keeppt-table-syncfrom complaining that it's changing data on a replica.
๐ง ALGORITHMS ๐ง
pt-table-sync has a generic data-syncing framework that uses different algorithms to find differences. the tool automatically picks the best algorithm for each table based on indexes, column types, and the algorithm preferences you specified with --algorithms. here's every algorithm available, listed in their default order of preference:
- Chunk โ finds an index whose first column is numeric (including date and time types), and divides the column's range of values into chunks of approximately
--chunk-sizerows. it syncs a chunk at a time by checksumming the entire chunk. if the chunk differs on the source and destination, it checksums each chunk's rows individually to find the rows that differ.
it's efficient when the column has sufficient cardinality to make the chunks end up about the right size.
the initial per-chunk checksum is quite small and results in minimal network traffic and memory consumption. if a chunk's rows must be examined, only the primary key columns and a checksum get sent over the network โ not the entire row. if a row is found to be different, then the entire row is fetched. but not before, bestie. ๐
note that this algorithm will not work if you're chunking a char column where all the values start with the same character. in that case, the tool will exit and suggest picking a different algorithm. ๐
- Nibble โ finds an index and ascends the index in fixed-size nibbles of
--chunk-sizerows, using a non-backtracking algorithm (seept-archiverfor more on this algorithm). it's very similar toChunk, but instead of pre-calculating the boundaries of each piece of the table based on index cardinality, it usesLIMITto define each nibble's upper limit, and the previous nibble's upper limit to define the lower limit.
it works in steps: one query finds the row that will define the next nibble's upper boundary, and the next query checksums the entire nibble. if the nibble differs between the source and destination, it examines the nibble row-by-row, just as Chunk does.
- GroupBy โ selects the entire table grouped by all columns, with a
COUNT(*)column added. compares all columns, and if they're the same, compares theCOUNT(*)column's value to determine how many rows to insert or delete into the destination. works on tables with no primary key or unique index. ๐ - Stream โ selects the entire table in one big stream and compares all columns. selects all columns. much less efficient than the other algorithms, but it works when there's no suitable index for them to use. it's giving "last resort but make it fashion". ๐
๐ฆ BIDIRECTIONAL SYNCING ๐ฆ
bidirectional syncing is an experimental feature. to make it work reliably there are a number of strict limitations:
- only works when syncing one server to other independent servers
- does not work in any way with replication
- requires that the table(s) are chunkable with the Chunk algorithm
- is not N-way, only bidirectional between two servers at a time
- does not handle
DELETEchanges
for example, suppose we have three servers: c1, r1, r2. c1 is the central server, a pseudo-source to the other servers (viz. r1 and r2 are not replicas to c1). r1 and r2 are remote servers. rows in table foo are updated and inserted on all three servers and we want to synchronize all the changes between all the servers. table foo has columns:
id int PRIMARY KEY
ts timestamp auto updated
name varchar
auto-increment offsets are used so that new rows from any server don't create conflicting primary key (id) values. in general, newer rows, as determined by the ts column, take precedence when a same-but-differing row is found during the bidirectional sync. "same but differing" means two rows have the same primary key (id) value but different values for some other column โ like the name column in this example. same-but-differing conflicts are resolved by a "conflict". a conflict compares some column of the competing rows to determine a "winner". the winning row becomes the source and its values are used to update the other row. ๐
there are subtle differences between three columns used to achieve bidirectional syncing that you should be familiar with: chunk column (--chunk-column), comparison column(s) (--columns), and conflict column (--conflict-column). the chunk column is only used to chunk the table; e.g. WHERE id >= 5 AND id < 10. chunks are checksummed and when chunk checksums reveal a difference, the tool selects the rows in that chunk and checksums the --columns for each row. if a column checksum differs, the rows have one or more conflicting column values. in a traditional unidirectional sync, the conflict is a moot point because it can be resolved simply by updating the entire destination row with the source row's values. in a bidirectional sync, though? the --conflict-column (in accordance with the other --conflict-* options listed below) is compared to determine which row is "correct" or "authoritative" โ and that row becomes the "source". ๐
to sync all three servers completely, two runs of pt-table-sync are required. the first run syncs c1 and r1, then syncs c1 and r2 including any changes from r1. at this point c1 and r2 are completely in sync, but r1 is missing any changes from r2 because c1 didn't have these changes when it and r1 were synced. so a second run is needed, which syncs the servers in the same order โ but this time when c1 and r1 are synced, r1 gets r2's changes. โจ
the tool does not sync N-ways, only bidirectionally between the first DSN given on the command line and each subsequent DSN in turn. so the tool in this example would be ran twice like:
pt-table-sync --bidirectional h=c1 h=r1 h=r2
the --bidirectional option enables this feature and causes various sanity checks to be performed. you must specify other options that tell pt-table-sync how to resolve conflicts for same-but-differing rows. those options are:
--conflict-column--conflict-comparison--conflict-value--conflict-threshold--conflict-error(optional)
use --print to test this option before --execute. the printed SQL statements will have comments saying on which host the statement would be executed if you used --execute. ๐ซถ
technical side note: the first DSN is always the "left" server and the other DSNs are always the "right" server. since either server can become the source or destination it's confusing to think of them as "src" and "dst". therefore they're generically referred to as left and right. it's easy to remember this because the first DSN is always to the left of the other server DSNs on the command line. ๐
โญ EXIT STATUS โญ
here are the exit statuses (also called return values, or return codes) for when pt-table-sync finishes and exits:
0โ Success. ๐1โ Internal error.2โ At least one table differed on the destination.3โ Combination of1and2.
โจ OPTIONS โจ
specify at least one of --print, --execute, or --dry-run.
--where and --replicate are mutually exclusive. (pick one, bestie, you can't have both ๐
)
this tool accepts additional command-line arguments. refer to the SYNOPSIS and usage information for details.
--algorithmsโ type: string; default:Chunk,Nibble,GroupBy,Stream
algorithm to use when comparing the tables, in order of preference.
for each table, pt-table-sync will check if the table can be synced with the given algorithms in the order that they're given. the first algorithm that can sync the table is used. see ALGORITHMS. ๐ง
--ask-passโ prompt for a password when connecting to MySQL.--bidirectionalโ enable bidirectional sync between first and subsequent hosts.
see BIDIRECTIONAL SYNCING for more information. ๐ฆ
--[no]bin-logโ default: yes
log to the binary log (SET SQL_LOG_BIN=1).
specifying --no-bin-log will SET SQL_LOG_BIN=0.
--buffer-in-mysqlโ instruct MySQL to buffer queries in its memory.
this option adds the SQL_BUFFER_RESULT option to the comparison queries. this causes MySQL to execute the queries and place them in a temporary table internally before sending the results back to pt-table-sync. the advantage of this strategy is that pt-table-sync can fetch rows as desired without using a lot of memory inside the Perl process, while releasing locks on the MySQL table (to reduce contention with other queries). the disadvantage is that it uses more memory on the MySQL server instead. ๐ฌ
you probably want to leave --[no]buffer-to-client enabled too, because buffering into a temp table and then fetching it all into Perl's memory is probably a silly thing to do. this option is most useful for the GroupBy and Stream algorithms, which may fetch a lot of data from the server.
--[no]buffer-to-clientโ default: yes
โฆokay so this option makes the tool fetch rows one-by-one from MySQL while it's comparing. ๐ข
It switches on mysql_use_result, which means MySQL keeps the selected rows chillin' on the server until the tool actually fetches them. Vibe: the tool uses less memory, but the rows stay locked on the server for longer. Trade-offs, bestie. ๐
If you disable it with --no-buffer-to-client, then mysql_store_result is used instead, which makes MySQL yeet all the selected rows at the tool at once. That might mean the results "cursor" stays open for a shorter time on the server โ but if the tables are big, it could take a long time anyway and eat all your memory. ๐ญ
For most non-trivial data sizes, you want to leave this option enabled. fr fr.
Heads up: this option is disabled when --bidirectional is used.
--[no]buffer-stdoutโ default: yes Turns on STDOUT buffering. ๐ Disable this one if you want to see live progress while using output post-processing tools liketeeorkubectl logsโ otherwise you're just staring at nothing and wondering if it's broken. ๐--channelโ type: string The channel name used when you're connected to a server that uses replication channels. ๐
Imagine this: you've got two sources โ source_a on port 12345, source_b on port 1236 โ and a replica connected to both of them using channels chan_source_a and chan_source_b. Now you wanna run pt-table-sync to sync the replica against source_a. Problem? pt-table-sync has no clue which one's the correct source, because SHOW REPLICA STATUS returns 2 rows and it's just standing there like ๐ตโ๐ซ. In that case you hit it with --channel=chan_source_a to specify the channel name to use in the SHOW REPLICA STATUS command. slay.
--charsetโ short form:-A; type: string The default character set. ๐ฆ If the value isutf8, it sets Perl's binmode on STDOUT toutf8, passes themysql_enable_utf8option toDBD::mysql, and runsSET NAMES UTF8after connecting to MySQL. Any other value sets binmode on STDOUT without the utf8 layer, and runsSET NAMESafter connecting to MySQL.--[no]check-child-tablesโ default: yes Checks whether--executeis gonna do child tables dirty. ๐ฌ When--replace,--replicate, or--sync-to-sourceis specified, the tool may sync tables usingREPLACEstatements. If a table being synced has child tables withON DELETE CASCADE,ON UPDATE CASCADE, orON UPDATE SET NULL, the tool prints an error and skips the table โ becauseREPLACEis literallyDELETEthenINSERT, so thatDELETEcascades to the child table and deletes its rows. Worst case? It can delete all the rows in child tables. ๐๐
Specify --no-check-child-tables to disable this check. And to completely avoid affecting child tables, also specify --no-foreign-key-checks so MySQL won't cascade any operations from the parent to child tables.
This check is only performed if --execute and one of --replace, --replicate, or --sync-to-source is specified. --print does not check child tables.
Also ngl, the error message only prints the first child table it finds with an ON DELETE CASCADE, ON UPDATE CASCADE, or ON UPDATE SET NULL foreign key constraint โ there could be other affected child tables lurking. ๐
--[no]check-masterโ default: yes Deprecated bestie โ this option is deprecated and will be removed in future releases. Use--[no]check-sourceinstead. โญ--[no]check-slaveโ default: yes Also deprecated and will be removed in future releases. Use--[no]check-replicainstead. โญ--[no]check-sourceโ default: yes With--sync-to-source, it tries to verify that the detected source is actually the real source. ๐--[no]check-replicaโ default: yes Checks whether the destination server is a replica.
If the destination server is a replica, making changes on it is generally unsafe. But sometimes you gotta โ like, --replace won't work unless there's a unique index, so in that scenario you can't make changes on the source. By default pt-table-sync will complain if you try to change data on a replica. Specify --no-check-replica to disable this check.
Use it at your own risk. ๐
--[no]check-triggersโ default: yes Checks that no triggers are defined on the destination table. ๐ธ
Triggers were introduced in MySQL v5.0.2, so for older versions this option has no effect because triggers won't be checked at all.
--chunk-columnโ type: string Chunk the table on this column. ๐--chunk-indexโ type: string Chunk the table using this index.--chunk-sizeโ type: string; default: 1000 Number of rows, or data size, per chunk. โจ
This is the size of each chunk of rows for the Chunk and Nibble algorithms. The size can be either a number of rows, or a data size. Data sizes are specified with a suffix of k=kibibytes, M=mebibytes, G=gibibytes. Data sizes get converted to a number of rows by dividing by the average row length. math girlie math ๐งฎ
--columnsโ short form:-c; type: array Compare this comma-separated list of columns. ๐--configโ type: Array Read this comma-separated list of config files. And psst โ if you specify it, it must be the first option on the command line. No exceptions, bestie. ๐--conflict-columnโ type: string Compare this column when rows conflict during a--bidirectionalsync. ๐ฆ
When a same-but-differing row is found, the value of this column from each row is compared according to --conflict-comparison, --conflict-value and --conflict-threshold to figure out which row has the correct data and becomes the source. The column can be any type that has an appropriate --conflict-comparison (this is almost all types except, for example, blobs โ blobs could never ๐).
This option only works with --bidirectional. See BIDIRECTIONAL SYNCING for more info.
--conflict-comparisonโ type: string Chooses the--conflict-columnwith this property as the source. ๐
This option decides how the --conflict-column values from the conflicting rows get compared. Possible comparisons are one of these MAGIC comparisons:
newestโ chooses the row with the newest temporal--conflict-columnvalueoldestโ chooses the row with the oldest temporal--conflict-columnvaluegreatestโ chooses the row with the greatest numerical--conflict-columnvalueleastโ chooses the row with the least numerical--conflict-columnvalueequalsโ--conflict-columnvalue equal to--conflict-valuematchesโ--conflict-columnvalue matching Perl regex pattern--conflict-value
This option only works with --bidirectional. See BIDIRECTIONAL SYNCING for more info.
--conflict-errorโ type: string; default: warn How to report unresolvable conflicts and conflict errors. ๐ญ
This option changes how you get notified when a conflict can't be resolved or causes some kind of error. Possible values are:
warn: print a warning to STDERR about the unresolvable conflictdie: die, stop syncing, and print a warning to STDERR
This option only works with --bidirectional. See BIDIRECTIONAL SYNCING for more info.
--conflict-thresholdโ type: string Amount by which one--conflict-columnmust exceed the other. ๐ฅ
--conflict-threshold stops a conflict from being resolved if the absolute difference between the two --conflict-column values is less than this amount. Example time: if two --conflict-column have timestamp values 2009-12-01 12:00:00 and 2009-12-01 12:05:00, the difference is 5 minutes. If --conflict-threshold is set to 5m the conflict will be resolved, but if --conflict-threshold is set to 6m the conflict will fail to resolve, because the difference is not greater than or equal to 6 minutes. In that latter case, --conflict-error reports the failure. periodt.
This option only works with --bidirectional. See BIDIRECTIONAL SYNCING for more info.
--conflict-valueโ type: string Use this value for certain--conflict-comparisons. ๐
This option gives the value for equals and matches --conflict-comparison.
This option only works with --bidirectional. See BIDIRECTIONAL SYNCING for more info.
--databasesโ short form:-d; type: hash Sync only this comma-separated list of databases. ๐
A super common request is syncing tables from one database with tables from another database, on the same server or a different one. That's not possible yet, bestie. --databases will not do it, and you can't do it with the D part of the DSN either โ because in the absence of a table name it assumes the whole server should be synced, and the D part controls only the connection's default database. So close yet so far ๐
--defaults-fileโ short form:-F; type: string Only read MySQL options from the given file. You must give an absolute pathname โ no shortcuts. ๐--dry-runAnalyze, decide which sync algorithm to use, print, and exit. ๐ง
Implies --verbose so you can actually see the results. The results come in the same output format you'd see from actually running the tool, but there will be zeros for rows affected. Why? Because the tool actually executes, but stops before it compares any data and just returns zeros. Those zeros do not mean there are no changes to be made. Don't let the zeros gaslight you. ๐
--enginesโ short form:-e; type: hash Sync only this comma-separated list of storage engines. โญ--executeExecutes queries to make the tables have identical data. ๐ฅ
This option makes pt-table-sync actually sync table data by executing all the queries it created to resolve table differences. Which meansโฆ the tables will be changed! ๐ฑ And unless you also specify --verbose, the changes will be made silently. If that's not what you want, go look at --print or --dry-run instead. Please. ๐
--explain-hostsPrints connection information and exits. ๐
It prints out a list of hosts to which pt-table-sync will connect, along with all the various connection options, and then exits. cute and informative.
--float-precisionโ type: int
okay so picking up right where we left off on that float-precision option, bestie โ it's about precision for FLOAT and DOUBLE number-to-string conversion โจ it causes FLOAT and DOUBLE values to be rounded to the specified number of digits after the decimal point, using the ROUND() function in MySQL. and like, why do you care? because it can help avoid checksum mismatches due to different floating-point representations of the same values on different MySQL versions and hardware ๐ซถ the default is no rounding โ the values get converted to strings by the CONCAT() function and MySQL picks the string representation itself, no cap. if you specify a value of 2, for example, then the values 1.008 and 1.009 will be rounded to 1.01, and will checksum as equal ๐
--[no]foreign-key-checksโ default:yes. Enables foreign key checks, i.e.SET FOREIGN_KEY_CHECKS=1. And specifying--no-foreign-key-checkswillSET FOREIGN_KEY_CHECKS=0๐ that's literally it, that's the whole vibe.--functionโ type: string. which hash function you'd like to use for checksums ๐ the default isCRC32. other good choices includeMD5andSHA1. and here's the fun part: if you have installed theFNV_64user-defined function,pt-table-syncwill detect it and prefer to use it, because it is much faster than the built-ins ๐ฅ you can also useMURMUR_HASHif you've installed that user-defined function. both of these are distributed with Percona Server. see pt-table-checksum for more information and benchmarks ๐--helpโ show help and exit. that's it, she's simple, she's iconic ๐--[no]hex-blobโ default:yes.HEX()yourBLOB,TEXTandBINARYcolumns ๐ฆ when row data from the source is fetched to create queries to sync the data (i.e. the queries seen with--printand executed by--execute), binary columns are wrapped inHEX()so the binary data does not produce an invalid SQL statement. you can disable this option but you probably shouldn't โ ๏ธ like, genuinely, don't.--hostโ short form:-h; type: string. connect to host. your classic, your main character ๐--ignore-columnsโ type: Hash. ignore this comma-separated list of column names in comparisons. this option causes columns not to be compared. however โ and this is the plot twist ๐ญ โ if a row is determined to differ between tables, all columns in that row will be synced, regardless. (it is not currently possible to exclude columns from the sync process itself, only from the comparison.) so it's a vibe check on the compare step, not a full exclusion, iykyk.--ignore-databasesโ type: Hash. ignore this comma-separated list of databases. and ngl, system databases such asinformation_schemaandperformance_schemaare already ignored by default ๐ซถ--ignore-enginesโ type: Hash; default:FEDERATED,MRG_MyISAM. ignore this comma-separated list of storage engines. bye felicia to those engines ๐--ignore-tablesโ type: Hash. ignore this comma-separated list of tables. table names may be qualified with the database name โจ--ignore-tables-regexโ type: string; group: Filter. ignore tables whose names match the Perl regex. regex girlies rise ๐ธ--[no]index-hintโ default:yes. addFORCE/USE INDEXhints to the chunk and row queries ๐ by defaultpt-table-syncadds aFORCE/USE INDEXhint to each SQL statement to coerce MySQL into using the index chosen by the sync algorithm or specified by--chunk-index. this is usually a good thing, but in rare cases the index may not be the best for the query, so you can suppress the index hint by specifying--no-index-hintand let MySQL choose the index. and listen โ this does not affect the queries printed by--print; it only affects the chunk and row queries thatpt-table-syncuses to select and compare rows ๐--lockโ type: int. lock tables:0=none,1=per sync cycle,2=per table, or3=globally. this usesLOCK TABLES. it can help prevent tables being changed while you're examining them ๐ the possible values are as follows:
VALUE MEANING
===== =======================================================
0 Never lock tables.
1 Lock and unlock one time per sync cycle (as implemented
by the syncing algorithm). This is the most granular
level of locking available. For example, the Chunk
algorithm will lock each chunk of N rows, and then
unlock them if they are the same on the source and the
destination, before moving on to the next chunk.
2 Lock and unlock before and after each table.
3 Lock and unlock once for every server (DSN) synced, with
FLUSH TABLES WITH READ LOCK.
a replication replica is never locked if --replicate or --sync-to-source is specified, since in theory locking the table on the source should prevent any changes from taking place. (you are not changing data on your replica, right? ๐) if --wait is given, the source (source) is locked and then the tool waits for the replica to catch up to the source before continuing.
if --transaction is specified, LOCK TABLES is not used. instead, lock and unlock are implemented by beginning and committing transactions. the exception is if --lock is 3 ๐
if --no-transaction is specified, then LOCK TABLES is used for any value of --lock. see --[no]transaction ๐
--lock-and-renameโ lock the source and destination table, sync, then swap names ๐ this is useful as a less-blockingALTER TABLE, once the tables are reasonably in sync with each other (which you may choose to accomplish via any number of means, including dump and reload or even something like pt-archiver). it requires exactly two DSNs and assumes they are on the same server, so it does no waiting for replication or the like. tables are locked withLOCK TABLES๐--mysql_sslโ short form:-s; type: int. create SSL MySQL connection ๐ฆ secure the bag.--passwordโ short form:-p; type: string. password to use when connecting. if password contains commas they must be escaped with a backslash:exam\,ple๐ญ yes really, escape the comma.--pidโ type: string. create the given PID file. the tool won't start if the PID file already exists and the PID it contains is different than the current PID. however, if the PID file exists and the PID it contains is no longer running, the tool will overwrite the PID file with the current PID โจ the PID file is removed automatically when the tool exits. clean up after yourself, queen ๐--portโ short form:-P; type: int. port number to use for connection.--printโ print queries that will resolve differences ๐ if you don't trustpt-table-sync, or just want to see what it will do, this is a good way to be safe. these queries are valid SQL and you can run them yourself if you want to sync the tables manually. honestly? the "look before you leap" option. iconic behaviour ๐ซถ--recursion-methodโ type: array; default:processlist,hosts. preferred recursion method used to find replicas. the possible methods are:
METHOD USES
=========== ==================
processlist SHOW PROCESSLIST
hosts SHOW REPLICAS (SHOW SLAVE HOSTS before MySQL 8.1)
dsn=DSN DSNs from a table
none Do not find replicas
the processlist method is the default, because SHOW REPLICAS is not reliable ๐ฌ however, if the server uses a non-standard port (not 3306), then the hosts method becomes the default because it works better in this case.
the hosts method requires replicas to be configured with report_host, report_port, etc.
the dsn method is special: rather than automatically discovering replicas, this method specifies a table with replica DSNs. the tool will only connect to these replicas. this method works best when replicas do not use the same MySQL username or password as the source, or when you want to prevent the tool from connecting to certain replicas ๐
the dsn method is specified like: --recursion-method dsn=h=host,D=percona,t=dsns. the specified DSN must have D and t parts, or just a database-qualified t part, which specify the DSN table. the DSN table must have the following structure:
CREATE TABLE `dsns` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`dsn` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
DSNs are ordered by id, but id and parent_id are otherwise ignored ๐ the dsn column contains a replica DSN like it would be given on the command line, for example: h=replica_host,u=repl_user,p=repl_pass.
the none method makes the tool ignore all replicas and cluster nodes. this method is not recommended because it effectively disables the REPLICA CHECKS and no differences can be found โ ๏ธ it is useful, however, if you only need to write checksums on the source or a single cluster node. the safer alternative is --no-replicate-check: the tool finds replicas and cluster nodes, performs the REPLICA CHECKS, but does not check for differences. see --[no]replicate-check ๐ซถ
--replaceโ write allINSERTandUPDATEstatements asREPLACE๐ฅ this is automatically switched on as needed when there are unique index violations. she adapts, she's flexible ๐--replicateโ type: string. sync tables listed as different in this table. specifies thatpt-table-syncshould examine the specified table to find data that differs. the table is exactly the same as the argument of the same name to pt-table-checksum. that is, it contains records of which tables (and ranges of values) differ between the source and replica ๐
for each table and range of values that shows differences between the source and replica, pt-table-sync will sync that table, with the appropriate WHERE clause, to its source โจ
this automatically sets --wait to 60 and causes changes to be made on the source instead of the replica ๐ซถ
if --sync-to-source is specified, the tool will assume the server you specified is the replica, and connect to the source as usual to sync.
otherwise, it will try to use SHOW PROCESSLIST to find replicas of the server you specified. if it is unable to find any replicas via SHOW PROCESSLIST, it will inspect SHOW REPLICAS instead. you must configure each replica's report-host, report-port and other options for this to work right ๐ after finding replicas, it will inspect the specified table on each replica to find data that needs to be synced, and sync it ๐
So back to that check โ the tool peeks at the source's copy of the table first, because it's assuming the source might be a replica too. ๐ Any table that shows differences there will NOT be synced on the replica(s). Example time: if your replication is set up as A->B, B->C, B->D, and you use this argument while specifying server B, the tool examines server B's copy of the table. If server B's data in table test.tbl1 looks different from server A's copy, the tool will not sync that table on servers C and D. Periodt. ๐
--slave-userโ type:string. This option is deprecated and will be removed in future releases. Use--replica-userinstead. ๐--slave-passwordโ type:string. This option is deprecated and will be removed in future releases. Use--replica-passwordinstead. ๐--replica-userโ type:string. Sets the user to be used to connect to the replicas. This parameter allows you to have a different user with less privileges on the replicas, but that user must exist on all replicas. ๐ซถ--replica-passwordโ type:string. Sets the password to be used to connect to the replicas. It can be used with--replica-userand the password for the user must be the same on all replicas. ๐--set-varsโ type:Array. Set the MySQL variables in this comma-separated list ofvariable=valuepairs.
By default, the tool sets:
wait_timeout=10000
Variables specified on the command line override these defaults. For example, specifying --set-vars wait_timeout=500 overrides the default value of 10000. The tool prints a warning and continues if a variable cannot be set. โ ๏ธ
--socketโ short form:-S; type:string. Socket file to use for connection. ๐--sync-to-masterโ This option is deprecated and will be removed in future releases. Use--sync-to-sourceinstead. ๐--sync-to-sourceโ Treat the DSN as a replica and sync it to its source. Treat the server you specified as a replica. InspectSHOW REPLICA STATUS, connect to the server's source, and treat the source as the source and the replica as the destination. Causes changes to be made on the source. Sets--waitto60by default, sets--lockto1by default, and disables--[no]transactionby default. See also--replicate, which changes this option's behavior. ๐--tablesโ short form:-t; type:hash. Sync only this comma-separated list of tables. Table names may be qualified with the database name. ๐--timeout-okโ Keep going if--waitfails. If you specify--waitand the replica doesn't catch up to the source's position before the wait times out, the default behavior is to abort. This option makes the tool keep going anyway.
โ ๏ธ Warning: if you are trying to get a consistent comparison between the two servers, you probably don't want to keep going after a timeout. ๐ญ
--[no]transactionโ Use transactions instead ofLOCK TABLES. The granularity of beginning and committing transactions is controlled by--lock. This is enabled by default, but since--lockis disabled by default, it has no effect.
Most options that enable locking also disable transactions by default, so if you want to use transactional locking (via LOCK IN SHARE MODE and FOR UPDATE), you must specify --transaction explicitly. If you don't specify --transaction explicitly, pt-table-sync will decide on a per-table basis whether to use transactions or table locks. It currently uses transactions on InnoDB tables, and table locks on all others. If --no-transaction is specified, then pt-table-sync will not use transactions at all (not even for InnoDB tables) and locking is controlled by --lock. When enabled, either explicitly or implicitly, the transaction isolation level is set REPEATABLE READ and transactions are started WITH CONSISTENT SNAPSHOT. ๐ง
--trimโTRIM()VARCHARcolumns inBIT_XORandACCUMmodes. Helps when comparing MySQL 4.1 to>= 5.0. This is useful when you don't care about the trailing space differences between MySQL versions which vary in their handling of trailing spaces. MySQL 5.0 and later all retain trailing spaces inVARCHAR, while previous versions would remove them. โ๏ธ--[no]unique-checksโ default:yes. Enable unique key checks (SET UNIQUE_CHECKS=1). Specifying--no-unique-checkswillSET UNIQUE_CHECKS=0. โ--userโ short form:-u; type:string. User for login if not current user. ๐ค--verboseโ short form:-v; cumulative:yes. Print results of sync operations. SeeOUTPUTfor more details about the output. ๐ฃ๏ธ--versionโ Show version and exit. ๐ท๏ธ--[no]version-checkโ default:yes. Check for the latest version of Percona Toolkit, MySQL, and other programs.
This is a standard "check for updates automatically" feature, with two additional features. First, the tool checks its own version and also the versions of the following software: operating system, Percona Monitoring and Management (PMM), MySQL, Perl, MySQL driver for Perl (DBD::mysql), and Percona Toolkit. Second, it checks for and warns about versions with known problems. For example, MySQL 5.5.25 had a critical bug and was re-released as 5.5.25a.
A secure connection to Perconaโs Version Check database server is done to perform these checks. Each request is logged by the server, including software version numbers and unique ID of the checked system. The ID is generated by the Percona Toolkit installation script or when the Version Check database call is done for the first time. Any updates or known problems are printed to STDOUT before the tool's normal output. This feature should never interfere with the normal operation of the tool. For more information, visit <https://www.percona.com/doc/percona-toolkit/LATEST/version-check.html>. ๐
--waitโ short form:-w; type:time. How long to wait for replicas to catch up to their source. Make the source wait for the replica to catch up in replication before comparing the tables. The value is the number of seconds to wait before timing out (see also--timeout-ok). Sets--lockto1and--[no]transactionto0by default.
If you see an error such as the following,
SOURCE_POS_WAIT returned -1
it means the timeout was exceeded and you need to increase it.
The default value of this option is influenced by other options. To see what value is in effect, run with --help. To disable waiting entirely (except for locks), specify --wait 0. This helps when the replica is lagging on tables that are not being synced. โณ
--whereโ type:string.WHEREclause to restrict syncing to part of the table. ๐ฏ--[no]zero-chunkโ default:yes. Add a chunk for rows with zero or zero-equivalent values. It only has an effect when--chunk-sizeis specified. The purpose of the zero chunk is to capture a potentially large number of zero values that would imbalance the size of the first chunk. For example, if a lot of negative numbers were inserted into an unsigned integer column causing them to be stored as zeros, then these zero values are captured by the zero chunk instead of the first chunk and all its non-zero values. 0๏ธโฃ
๐ DSN OPTIONS ๐
These DSN options are used to create a DSN. Each option is given like option=value. The options are case-sensitive, so P and p are not the same option. There cannot be whitespace before or after the = and if the value contains whitespace it must be quoted. DSN options are comma-separated. See the percona-toolkit manpage for full details. ๐ง
Aโdsn: charset; copy: yes. Default character set. ๐Dโdsn: database; copy: yes. Database containing the table to be synced. ๐๏ธFโdsn: mysql_read_default_file; copy: yes. Only read default options from the given file. ๐hโdsn: host; copy: yes. Connect to host. ๐ฅ๏ธpโdsn: password; copy: yes. Password to use when connecting. If password contains commas they must be escaped with a backslash:exam\,ple. ๐Pโdsn: port; copy: yes. Port number to use for connection. ๐ขSโdsn: mysql_socket; copy: yes. Socket file to use for connection. ๐tโcopy: yes. Table to be synced. ๐uโdsn: user; copy: yes. User for login if not current user. ๐คsโdsn: mysql_ssl; copy: yes. Create SSL connection. ๐
๐ฆ ENVIRONMENT ๐ฆ
The environment variable PTDEBUG enables verbose debugging output to STDERR. To enable debugging and capture all output to a file, run the tool like:
PTDEBUG=1 pt-table-sync ... > FILE 2>&1
Be careful: debugging output is voluminous and can generate several megabytes of output. ๐ญ
๐ ATTENTION ๐
Using PTDEBUG might expose passwords. When debug is enabled, all command line parameters are shown in the output. ๐
๐ง SYSTEM REQUIREMENTS ๐ง
You need Perl, DBI, DBD::mysql, and some core packages that ought to be installed in any reasonably new version of Perl. ๐ ๏ธ
๐ BUGS ๐
For a list of known bugs, see <https://jira.percona.com/projects/PT/issues>. ๐
Please report bugs at <https://jira.percona.com/projects/PT>. Include the following information in your bug report:
- Complete command-line used to run the tool
- Tool
--version - MySQL version of all servers involved
- Output from the tool including STDERR
- Input files (log/dump/config files, etc.)
If possible, include debugging output by running the tool with PTDEBUG; see ENVIRONMENT. ๐ซถ
๐ DOWNLOADING ๐
Visit <http://www.percona.com/software/percona-toolkit/> to download the latest release of Percona Toolkit. Or, get the latest release from the command line:
wget percona.com/get/percona-toolkit.tar.gz
wget percona.com/get/percona-toolkit.rpm
wget percona.com/get/percona-toolkit.deb
You can also get individual tools from the latest release:
wget percona.com/get/TOOL
Replace TOOL with the name of any tool. ๐
๐ AUTHORS ๐
Baron Schwartz โจ
๐ ACKNOWLEDGMENTS ๐
Okay so bestie, none of this was conjured out of thin air, and the author is being super classy about saying so. Receipts time:
This work is based in part on Giuseppe Maxia's work on distributed databases โ http://www.sysadminmag.com/articles/2004/0408/ โ plus code derived from that article. There's more explanation, and a link to the code, at http://www.perlmonks.org/?node_id=381053.
Another programmer extended Maxia's work even further: Fabien Coelho changed and generalized Maxia's technique, introducing symmetry and avoiding some problems that might have caused too-frequent checksum collisions ๐ญ. That work grew into pg_comparator, http://www.coelho.net/pg_comparator/. Coelho also explained the technique further in a paper titled "Remote Comparison of Database Tables" (http://cri.ensmp.fr/classement/doc/A-375.pdf).
So here's the plot twist ๐: this existing literature mostly addressed how to find the differences between tables โ not how to resolve them once found. The author needed a tool that would not only find them efficiently, but would then resolve them. Thinking about how to improve the technique further first showed up in this article:
โ where a number of problems with the Maxia/Coelho "bottom-up" algorithm got discussed. After writing that article, this tool got started. The goal was to actually implement their algorithm with some improvements, so the author was sure they understood it completely. And then: discovered it is not what they thought it was, and is considerably more complex than it appeared at first ๐ญ๐ญ. Fabien Coelho was kind enough to address some questions over email ๐ซถ.
The first versions of this tool implemented a version of the Coelho/Maxia algorithm, which the author called "bottom-up", and their own, which they called "top-down." Those algorithms are considerably more complex than the current algorithms and have been removed from this tool, and may be added back later. The improvements to the bottom-up algorithm are the author's original work, as is the top-down algorithm. The techniques to actually resolve the differences are also the author's own work. Slay, honestly ๐ .
Another tool that can synchronize tables is the SQLyog Job Agent from webyog. Thanks to Rohit Nadhani, SJA's author, for the conversations about the general techniques. There is a comparison of pt-table-sync and SJA at https://web.archive.org/web/20070919024435/http://www.xaprb.com/blog/2007/04/05/mysql-table-sync-vs-sqlyog-job-agent/.
Thanks to the following people and organizations for helping in many ways ๐ซถโจ:
- The Rimm-Kaufman Group
http://www.rimmkaufman.com/ - MySQL AB
http://www.mysql.com/ - Blue Ridge InternetWorks
http://www.briworks.com/ - Percona
http://www.percona.com/ - Fabien Coelho
- Giuseppe Maxia and others at MySQL AB
- Kristian Koehntopp (MySQL AB)
- Rohit Nadhani (WebYog)
- The helpful monks at Perlmonks
- And others too numerous to mention.
๐ ABOUT PERCONA TOOLKIT ๐
This tool is part of Percona Toolkit, a collection of advanced command-line tools for MySQL developed by Percona. Percona Toolkit was forked from two projects in June, 2011: Maatkit and Aspersa. Those projects were created by Baron Schwartz and primarily developed by him and Daniel Nichter. Visit http://www.percona.com/software/ to learn about other free, open-source software from Percona. iykyk ๐
๐ COPYRIGHT, LICENSE, AND WARRANTY ๐
This program is copyright 2011-2026 Percona LLC and/or its affiliates, 2007-2011 Baron Schwartz.
THE LEGAL BIT, and no we're not paraphrasing this one, bestie โ THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Like, zero promises. None. ๐
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2; OR the Perl Artistic License. On UNIX and similar systems, you can issue man perlgpl or man perlartistic to read these licenses ๐.
You should have received a copy of the GNU General Public License, version 2 along with this program; if not, see https://www.gnu.org/licenses/.
โญ VERSION โญ
pt-table-sync 3.7.1-4
๐ POD ERRORS ๐
Hey! The above document had some coding errors, which are explained below:
Around line 13201:
Non-ASCII character seen before =encoding in 'Perconaโs'. Assuming UTF-8
literally the most Gen Z error ever โ the doc was too cute with a curly apostrophe and the parser was like "bestie, encoding???" ๐ญ๐
okay that's the whole page, you made it ๐๐ซถ this was pt-table-sync from Percona Toolkit, source perl v5.42.2, dated 2026-09-01 โ go sync some tables, but like, carefully (re-read ATTENTION first, fr fr). bye bestie ๐
โจ๐
๐ฆ where this page comes from
- arch rolling: percona-toolkit 3.7.1_4-1 ยท GPL
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms