Settings v2
General Settings
logical_replication_mode
: Affects how the program interprets connections and table filter settings (see more details below), and also what requirements to check for in the connections before starting the comparison. Currently the possible values are:all_bdr_nodes
: Iflogical_replication_mode
is set tobdr
, then it is possible to specify only the Initial Connection (see below) and let LiveCompare build the connection list based on the current list of active BDR nodes. Default:off
.max_parallel_workers
: Number of parallel processes to be considered. Each process will work on a table from the queue. Default:2
.
Important: Each process will keep N+1 open connections: 1 to each data connection and another 1 to the output database.
buffer_size
: Number of rows to be retrieved from the tables on every data fetch operation. Default:4096
.log_level
: Verbosity level in the log file. Possible values:debug
,info
,warning
orerror
. Default:info
.data_fetch_mode
: Affects how LiveCompare fetches data from the database.prepared_statements
: Uses prepared statements (a query withLIMIT
) for data fetch. Only a very small amount of data (buffer_size = 4096
rows by default) is fetched each time, so it has the smallest impact of all 3 modes, and by the same reason it's the safer fetch mode. Allows asynchronous data fetch (defined byparallel_data_fetch
). For the general use case, this fetch method provides a good performance, but a performance decrease can be felt for large tables. This is the default and strongly recommended when server load is medium-high.server_side_cursors_with_hold
: Uses server-side cursorsWITH HOLD
for data fetch. As table data is retrieved in a single transaction, it holds backxmin
and can cause bloat and replication issues, and also preventVACUUM
from running well. Also, theWITH HOLD
clause tells Postgres to materialize the query (workers may hang for a few seconds waiting for the data to be materialized), so the whole table data consumes RAM and can be stored on Postgres side disk as temporary files. All that impact can be decreased by usingparallel_chunk_rows
(disabled by default), and speed can be improved by increasingbuffer_size
a little. Allows asynchronous data fetch (defined byparallel_data_fetch
). For the general use case, this fetch method doesn't provide any benefits when compared toprepared_stataments
, but for multiple small tables it's faster. However, this mode is recommended only when load is very low, for example on tests and migration scenarios.server_side_cursors_without_hold
: Uses server-side cursorsWITHOUT HOLD
for data fetch. Asserver_side_cursors_with_hold
, this mode can also hold backxmin
, thus potentially can cause bloat,VACUUM
and replication issues on Postgres, but such impact is higher becauseWITHOUT HOLD
cursors require an open transaction for the whole comparison session (this will be lifted in further versions). As the snapshot is held for the whole comparison session, comparison results might be helpful depending on your use case. As the query is not materialized, memory usage and temp file generation remains low. Asynchronous data fetch is not allowed. In terms of performance, this mode is slower for the general use case, but for large tables it can be the faster. It's recommended when load on the database is low-medium.
Important: the choice of the right data_fetch_mode
for the right scenario
is very important. Using prepared statements has the smallest footprint on the
database server, so it's the safest approach, and it's good for the general use
case. Another point is that prepared statements allow LiveCompare to always see
the latest version of the rows, which may not happen when using server-side
cursors on a busy database. So it's recommended to use prepared_statements
for
production, high load servers; and either server_side_cursors_*
settings for
testing, migration scenarios, and low load servers. The best strategy would
probably mix server_side_cursors_without_hold
for very large tables, and
prepared_statements
for the remaining tables. Refer to the table below for
a comparison on the cost/benefit ratio:
prepared_statements | server_side_cursors_with_hold | server_side_cursors_without_hold | |
---|---|---|---|
xmin hold | very low | medium | high |
xmin released per | buffer | chunk | whole comparison session |
temp files | very low | very high | low |
memory | very low | high | low |
allows async conns | yes | yes | no |
fastest for | general | small tables | large tables |
recommended load | high | very low | low-medium |
Note about Oracle: For Oracle, the data_fetch_mode
setting is completely
ignored, and data will always be fetch from Oracle using a direct query, and
data is taken in chunks of buffer_size
through the client-side cursor.
parallel_chunk_rows
: Minimum number of rows required to consider splitting a table into multiple chunks for parallel comparison. A hash is used to fetch data, so workers don't clash with each other. Each table chunk will have no more thanparallel_chunk_rows
rows. Setting it to any value < 1 disables table splitting. Default: 0 (disabled).
Important: While table splitting can help a large table to be compared in
parallel by multiple workers, performance for each worker can be impacted by
the hash condition being applied to all rows. Depending on the Postgres
configuration (specially with the default of random_page_cost = 4
, which can
be considered too conservative for modern hard drives), the Postgres query
planner can incorrectly prefer Bitmap Heap Scans, and if the database is
running on SSD, disabling Bitmap Heap Scan on LiveCompare can significantly
improve the comparison performance. This can be done per connection with the
start_query
setting:
parallel_data_fetch
: If data fetch should be performed in parallel (i.e., using async connections to the databases). Improves performance of multi-way comparison. If any data connections are not PostgreSQL, then this setting is automatically disabled. It's only allowed whendata_fetch_mode = prepared_statements
ordata_fetch_mode = server_side_cursors_with_hold
. Default:on
.comparison_algorithm
: Affects how LiveCompare works through table rows to compare data. Using hashes is faster than full row comparison. It can assume one of the following values:min_time_between_heart_beats
: Time in seconds to wait before logging a "Heart Beat" message to the log. Each worker tracks it separately per round part being compared. Default: 30 seconds.min_time_between_round_saves
: Time in seconds to wait before updating each round state when the comparison algorithm is in progress. A round save can only happen during a heart beat, somin_time_between_round_saves
should be greater than or equalmin_time_between_heart_beats
. Note that when the round finishes, LiveCompare always updates the round state for that table. Default: 60 seconds.
Important: If the user cancels execution of LiveCompare by hitting Ctrl-c
and starts it again, then LiveCompare will resume the round for that table,
starting from the point where the round state was saved.
comparison_cost_limit
: if > 0, corresponds to a number of rows each worker will process before taking a nap ofcomparison_cost_delay
seconds. Defaults to 0, meaning that each worker will process rows without taking a nap.comparison_cost_delay
: ifcomparison_cost_limit > 0
, then this setting specifies how long each worker should sleep. Defaults to0.0
.stop_after_time
: Time in seconds after which LiveCompare will automatically stop itself as if the user had hitCtrl-c
. The comparison session that was interrupted, if not finished yet, can be resumed again by passing the session ID as argument in the command line. Default isstop_after_time = 0
, which means that automatic interruption is disabled.consensus_mode
: Consensus algorithm used by LiveCompare to determine which data connections are divergent. Possible values aresimple_majority
,quorum_based
orsource_of_truth
. Ifconsensus_mode = source_of_truth
thendifference_sources_of_truth
must be filled. Default issimple_majority
.difference_required_quorum
: Ifconsensus_mode = quorum_based
, then this setting specified the minimum quorum is required to decide which connections are divergent. Should be a number between 0.0 and 1.0 (0.0 means no connection is required while 1.0 means all connections are required, both cases are extreme and should not be used). The default value is 0.5, and we recommend using a value close to that.difference_sources_of_truth
: Comma-separated list of connections names (or node names, iflogical_replication_mode = bdr
andall_bdr_nodes = on
) that should be considered as source of truth. It is only used whenconsensus_mode = source_of_truth
. For example:difference_sources_of_truth = node1,node2
. In this example, either the sectionsnode1 Connection
andnode2 Connection
should be defined in the .ini file orall_bdr_nodes = on
and only theInitial Connection
is defined, whilenode1
andnode2
should be valid BDR node names.difference_tie_breakers
: Comma-separated list of connection names (or node names, iflogical_replication_mode = bdr
andall_bdr_nodes = on
) that should be considered as tie breakers whenever the consensus algorithm finds a tie situation. For example:difference_tie_breakers = node1,node2
. In this example, either the sectionsnode1 Connection
andnode2 Connections
should be defined in the .ini file orall_bdr_nodes = on
and only theInitial Connection
is defined, whilenode1
andnode2
should be valid BDR node names. Default is to not consider any connection as tie breaker.difference_statements
: Controls what kind of DML statements will be generated by LiveCompare. The value ofdifference_statements
can be one of:difference_allow_null_updates
: Determines whether commands likeUPDATE SET col = NULL
will be allowed in the difference report. Default:on
.difference_statement_order
: Controls order of DML statements that will be generated by LiveCompare. The value ofdifference_statement_order
can be one of:difference_fix_replication_origin
: When working with BDR databases, for difference LiveCompare will create a specific replication origin if it doesn't exist yet, then use the replication origin to create apply script with DML fixes. The settingdifference_fix_replication_origin
specifies the name of the replication origin used by LiveCompare. If the user doesn't set any value for this setting, then LiveCompare will automatically setdifference_fix_replication_origin = bdr_local_only_origin
. Note that the replication origin that LiveCompare creates is not dropped to allow verification after the comparison, but if needed the replication origin can be manually dropped later. Requireslogical_replication_mode = bdr
.
IMPORTANT: Please note that BDR 3.6.18 introduced the new pre-created
bdr_local_only_origin
replication origin to be used for applying local-only
transactions. So if LiveCompare is connected to BDR 3.6.18, it won't create this
replication origin, and it is recommended that the user should not try to drop
this replication origin.
difference_fix_start_query
: Arbitrary query that is executed at the beginning of the apply script generated by LiveCompare. Additionally if a BDR comparison is being performed and thedifference_fix_start_query
is empty, then LiveCompare also automatically does the following:show_progress_bars
: Determines whether or not progress bars should be shown in the console output. Disabling this setting might be useful for batch executions. Default:on
.output_schema
: In the output connection, the schema where the comparison report tables will be created. Default:livecompare
.hash_column_name
: Every data fetch will contain a specific column which is the hash of all actual columns in the row. This setting specifies the name of this column. Default:livecompare_hash
.rownumber_column_name
: Some fetches need to use therow_number()
function value inside a query column. This setting specifies the name of this column. Default:livecompare_rownumber
.fetch_row_origin
: When this setting is enabled, LiveCompare fetches the origin name for each divergent row, which might be useful for debugging purposes. Default:off
. To be enabled, requireslogical_replication_mode
set topglogical
orbdr
.column_intersection
: When this setting is enabled, for a given table that is being compared, LiveCompare will only work on the intersection of columns from the table on all connections, ignoring extra columns that might exist on any of the connections. When this setting is disabled, LiveCompare will check if columns are equivalent on the table on all connections, and abort the comparison of the table if there are any column mismatches. Default:off
.
Important: If table has PK, then the PK columns are not allowed to be
different, even if column_intersection = on
.
ignore_nullable
: If for a specific table comparison, LiveCompare is using a Comparison Key different than the Primary Key, then LiveCompare requires all columns to beNOT NULL
ifignore_nullable
is enabled (default). It's possible to override that behavior by settingignore_nullable = off
, which will allow LiveCompare to consider null-able columns in the comparison, which in some corner cases can produce false positives.check_uniqueness_enforcement
: If LiveCompare is using an user-defined Comparison Key or using all columns in the table as a Comparison Key, then LiveCompare checks for table uniqueness on the Comparison Key if settingcheck_uniqueness_enforcement
is enabled (default).oracle_ignore_unsortable
: When enabled, tells LiveCompare to ignore columns with Oracle unsortable data types (BLOB, CLOB, NCLOB, BFILE) if column is not part of the table PK. If enabling this setting, it is recommended to also enablecolumn_intersection
.oracle_user_tables_only
: When enabled, tells LiveCompare to fetch table metadata only from the Oracle logged in user, which is faster because it reads, for example, fromsys.user_tables
andsys.user_tab_columns
instead ofsys.all_tables
andsys.all_tab_columns
. Default:off
.oracle_fetch_fk_metadata
: When enabled, tells LiveCompare to fetch foreign key metadata, which can be a slow operation. Overrides the value of the settingfetch_fk_metadata
on the Oracle connection. Default:off
.schema_qualified_table_names
: Table names are treated as schema-qualified when this setting is enabled. Disabling it allows comparison of tables without using schema-qualified table names: on Oracle x Postgres comparisons, it requires also enablingoracle_user_tables_only
, while on Postgres x Postgres, it allows for comparisons of tables that are under different schemas, even in the same database. Also, whenschema_qualified_table_names
is enabled,Table Filter -> tables
,Row Filter
andColumn Filter
allow table name without the schema name. Default:on
.force_collate
: When set to a value other thanoff
and to a valid collation name, forces the specified collation name inORDER BY
operations in all Postgres databases being compared. Useful when comparing Postgres databases with different collation or when comparing Oracle versus Postgres databases (in this case users should setforce_collate = C
). Will assume valueC
if comparing mixed technologies (like Oracle vs PostgreSQL) and no collation is specified. Default:off
.work_directory
: path to theLiveCompare
working directory. The session folder containing output files will be created in such directory. Default:.
(current directory).abort_on_setup_error
: when enabled, if LiveCompare hits any error when trying to setup a table comparison round, the whole comparison session is aborted. Default:off
.
Important: Setting abort_on_setup_error
is only considered during
compare
mode. In recheck
mode, LiveCompare always aborts at the first error
in setup.
custom_dollar_quoting_delimiter
: when LiveCompare finds differences, it will output the DML using dollar quoting on strings. The default behavior is create a random string to compose it. If you want by any means use a custom one, you can set this parameter as the delimiter to be used. You just need to set the constant, not the$
symbols around the constant. Defaults tooff
, which means LiveCompare will use amd5
hash of the wordLiveCompare
.session_replication_role_replica
: when enabled LiveCompare will usesession_replication_role
PostgreSQL setting asreplica
in the output apply scripts. That's useful if you want to prevent firing triggers and rules while applying DML in the nodes with divergences. Enabling it requires a PostgreSQL super user, otherwise will take no effect. Defaults tooff
.split_updates
: when enabled LiveCompare will splitUPDATE
divergences, i.e., instead of generating aUPDATE
DML, it will generate correspondingDELETE
andINSERT
in the apply script. Defaults tooff
.float_point_round
: an integer to specify decimal digits that LiveCompare should round when comparing float point values coming from the database. Default is -1, which disables float point rounding.
Initial Connection
The initial connection is used only when logical_replication_mode
is set to
pglogical
or bdr
, and is used only when the program starts, to fetch DSN
from node names, if the user has set data connections using only the node_name
setting.
technology
: RDBMS technology. Currently the only possible value ispostgresql
.dsn
: PostgreSQL connection string. Ifdsn
is set, thenhost
,port
,dbname
anduser
are ignored. Thedsn
setting can also have all other parameter key words allowed by libpq.host
: Server address. Leave empty to use the Unix socket connection.port
: Port. Default:5432
.dbname
: Database name. Default:postgres
.user
: Database user. Default:postgres
.application_name
. Application name. Can be used even if the user setdsn
instead of all other connection information. Default:livecompare_initial
.
Output Connection
The output connection specifies where LiveCompare will create the comparison report tables.
technology
: RDBMS technology. Currently the only possible value ispostgresql
.dsn
: PostgreSQL connection string. Ifdsn
is set, thenhost
,port
,dbname
anduser
are ignored. Thedsn
setting can also have all other parameter key words allowed by libpq.host
: Server address. Leave empty to use the Unix socket connection.port
: Port. Default:5432
.dbname
: Database name. Default:postgres
.user
: Database user. Default:postgres
.application_name
. Application name. Can be used even if the user setdsn
instead of all other connection information. Default:livecompare_output
.
Data Connection
A "data connection" is a connection section similar to the Initial Connection
and the Output Connection
, but LiveCompare effectively fetches and compares
data on the data connections.
Similarly to the Initial Connection
and Output Connection
, a "data
connection" is defined in a named section. The section name should be of the
form Name Connection
, being Name
any single-worded string starting with an
alphabetic character. In this case, whatever the user fills in Name
is called
the "Connection ID" of the data connection. It is also required that each data
connection has an unique Connection ID in the whole list of data connections.
If logical_replication_mode = bdr
and all_bdr_nodes = on
, then the user is
not required to specify any data connection, because LiveCompare will build the
data connection list by fetching BDR metadata from the Initial Connection
.
technology
: RDBMS technology. Currently possible values arepostgresql
ororacle
.node_name
: Name of the node in the cluster. Requireslogical_replication_mode
set topglogical
orbdr
, and also requires that theInitial Connection
is filled. Ifnode_name
is set, thendsn
,host
port
,dbname
anduser
settings are all ignored.dsn
: PostgreSQL connection string. Ifdsn
is set, thenhost
,port
,dbname
anduser
are ignored. Thedsn
setting can also have all other parameter key words allowed by libpq.host
: Server address. Leave empty to use the Unix socket connection.port
: Port. Default:5432
.dbname
: Database name. Default:postgres
.service
: Service name, used in Oracle connections. Default:XE
.user
: Database user. Default:postgres
.password
: Plain text password. We recommend not to use this, but in some legacy connections it might be required.application_name
. Application name. Can be used even if the user setdsn
ornode_name
instead of all other connection information. Default:livecompare_<Connection ID>
.start_query
: Arbitrary query that is executed each time a connection to a database is open.fetch_fk_metadata
: If LiveCompare should gather metadata about foreign keys on the connection. Default:on
.
Table Filter
If omitted or left empty, this section from the .ini
file will mean that
LiveCompare should be executed against all tables in the first database.
If you want LiveCompare to be executed against a specific set of tables, there are different ways to specify this:
publications
: You can filter specific publications, and LiveCompare will use only the tables associated to those publications. The variablepublication_name
can be used to build the conditional expression, for example:
Requires logical_replication_mode = native
.
replication_sets
: When using pglogical or BDR, you can filter specific replication sets, and LiveCompare will work only on the tables associated to those replication sets. The variableset_name
can be used to build the conditional expression, for example:
Requires logical_replication_mode = pglogical
or
logical_replication_mode = bdr
.
schemas
: You can filter specific schemas, and LiveCompare will work only on the tables that belong to those schemas. The variableschema_name
can be used to build the conditional expression, for example:
tables
: The variabletable_name
can help you build a conditional expression to filter only the tables you want LiveCompare to work on, for example:
Please note that, in any conditional expression, the %
character should be
escaped as %%
.
The table name should be schema-qualified, unless schema_qualified_table_names
is disabled. For example, it's possible to filter only a specific list of
tables:
If you have disabled general setting schema_qualified_table_names
, then you
should also set an appropriate search_path
for Postgres in the connection
start_query
setting, for example:
IMPORTANT: Please note that if two or more schemas that were set on search_path
contains a table if the same name, just the first one found will be considered
in the comparison.
The Table Filter
section can have a mix of publications
, replication_sets
,
schemas
and tables
filters, and LiveCompare will consider the set of tables
that are in the intersection of all filters you specified. For example:
Also please note that the table filter is applied in the first database, to build the table list. If a table exists in the first database and is being considered in the filter, but does not exist in any other database, then you will see something like this in the logs, and the comparison for that specific table will be skipped.
Similarly, if a table exists in any other database but does not exist in the first database, then it won't be considered in the comparison, even if you didn't apply any table filter.
A comparison for a specific table will also be skipped if the table column names
are not exactly the same (unless column_intersection
is enabled), and in the
same order. An appropriate message will be included in the log file as well.
Currently LiveCompare does not check if data types nor constraints are the same on both tables.
IMPORTANT: please note that conflicts
mode doesn't make use of table filter.
Row Filter
In this section you can apply a row-level filter to any table, so LiveCompare will work only on the rows that satisfy the row filter.
You can write a list of tables under this section, one table per line (all
table names should be schema qualified unless schema_qualified_table_names
is
disabled), for example:
In this case, for the table public.table1
, LiveCompare will work only in the
rows that satisfy the clause id = 10
, while for the table public.table2
,
only rows that satisfy logdate >= '2000-01-01
will be considered in the
comparison.
If you have disabled general setting schema_qualified_table_names
, then you
should also set an appropriate search_path
for Postgres in the connection
start_query
setting, for example:
Any kind of SQL condition (same as you would put in the WHERE
clause) is
accepted, in the same line, as the table row filter. For example, if you have a
large table and want to compare only a specific number of IDs, it's possible to
create a temporary table with all the IDs. Then you can use an IN
clause to
emulate a JOIN
, like this:
If a row filter is written incorrectly, then LiveCompare will try to apply the filter but will fail. So the comparison for this specific table will be skipped, and an exception will be written to the log file.
If a table is listed in the Row Filter
section, but somehow got filtered out
by the Table Filter
, then the row filter for this table will be silently
ignored.
IMPORTANT: please note that conflicts
mode doesn't make use of row filter.
Using current timestamp in Row Filter
The Row Filter
is applied differently depending on the data_fetch_mode
:
- On Postgres, setting
data_fetch_mode
toserver_side_cursors_with_hold
orserver_side_cursors_without_hold
will cause theRow Filter
to be applied only at the beginning of the table comparison, when the query is executed. This means that using a server-side cursor to fetch data ensures the data is seen as a snapshot of how it was beginning of the comparison. - On Postgres, setting
data_fetch_mode
toprepared_statements
(the default) causes theRow Filter
to be included in the prepared query, which is then executed at every data buffer that is fetched. Which means that, if the query usesnow()
,CURRENT_TIMESTAMP
orSYSDATE
(on EPAS) on theRow Filter
, then when the prepared statement is executed, Postgres will re-evaluate the current timestamp.
So, when using now()
, CURRENT_TIMESTAMP
or SYSDATE
on the Row Filter
,
for example:
Then it is also required to use a server-side cursor to ensure the current
timestamp is evaluated only at the beginning of the queries. In other words,
it is required that data_fetch_mode
is set to a value different than
prepared_statements
.
On Oracle, as explained above, the data_fetch_mode
setting is ignored, and
the query is executed at the beginning, then data is fetch via the client-side
cursor. This ensures data is seen as a snapshot of how it was at the beginning
of the comparison. This is a client-side cursor, but the behavior is similar of
using a server-side cursor in Postgres.
Column Filter
In this section you can apply a column-level filter to any table, so LiveCompare will work only on the columns that are not part of the column filter.
You can write a list of tables under this section, one table per line (all
table names should be schema qualified unless schema_qualified_table_names
is
disabled). For example, considering both public.table1
and public.table2
have
the columns column1
, column2
, column3
, column4
and column5
:
In this case, for the table public.table1
, LiveCompare will work only in the
columns column2
, column4
and column5
, filtering out column1
and column3
,
while for the table public.table2
, only the columns column2
, column3
and
column4
will be considered in the comparison, filtering out column1
and column5
.
If you have disabled general setting schema_qualified_table_names
, then you
should also set an appropriate search_path
for Postgres in the connection
start_query
setting, for example:
If absent column names are given in the column filter, that is, column doesn't exist in the given table, then LiveCompare will log a message about the columns that could not be found and ignore them, using just the valid ones, if any.
If a table is listed in the Column Filter
section, but somehow got filtered
out by the Table Filter
, then the column filter for this table will be
silently ignored.
IMPORTANT: Please note that if a column specified in a Column Filter
is
part of the table PK, then it won't be ignored in the comparison. LiveCompare
will log that and ignore the filter of such column.
IMPORTANT: please note that conflicts
mode doesn't make use of column filter.
Comparison Key
New feature
LiveCompare Comparison Key support is available in LiveCompare version 2.0 and later.
Similarly to the Column Filter
, in this section you can also specify a list
of columns per table. These columns will be considered as a Comparison Key for
the specific table, even if the table has a Primary Key or UNIQUE
constraint.
For example:
In the example above, for table public.table1
, the Comparison Key will be
columns col_a
and col_b
. For table public.table2
, columns c1
and c2
will
considered as a Comparison Key.
The same behavior about missing columns or filtered out or missing tables that
are explained in the Column Filter
section above, also apply to the Comparison
Key
. Similarly, the Comparison Key
section is ignored in Conflicts Mode.
Conflicts Filter
In this section you can specify a filter to be used in --conflicts
mode while
fetching conflicts from BDR nodes. You can build any SQL conditional expression,
and use below fields in the expression:
origin_node
: the upstream node of the subscriptiontarget_node
: the downstream node of the subscriptionlocal_time
: the timestamp when the conflict occurred in the nodeconflict_type
: the type of the conflictconflict_resolution
: the resolution which was appliednspname
: schema name of the involved relationrelname
: relation name of the involved relation
You must use conflicts
attribute under the section. Please find an example below:
By adding above piece of configuration to your INI file, LiveCompare would fetch
just conflicts that are of type update_missing
, and related to tables under
schema my_schema
while querying for conflicts in each of the BDR nodes.
IMPORTANT: Please note that this section is exclusive for --conflicts
mode.