max_wal_size is not a maximum, and it is not the size of anything you can du. It is a checkpoint trigger denominated in bytes: once the WAL written since the last checkpoint started reaches a fixed fraction of this value (the fraction is below, and it is not 1), the next one starts, whether or not checkpoint_timeout has come
Errata: the max_connections post told you to size that parameter for “the replication connections.” On 12 and later, don’t. WAL senders have their own seats, sized by this parameter, and have not drawn from max_connections since PostgreSQL 12. The rest of that post stands; that clause is wrong for every version you should be running.
max_sync_workers_per_subscription is how many tables a subscription copies at once. It is not how fast the initial copy goes, which is what people raise it hoping for. Each table synchronization worker copies exactly one table, start to finish, so the parameter buys parallelism across tables and nothing within one. Your largest table takes as long as it takes with this
max_standby_streaming_delay is not a query timeout, whatever its name and its default suggest. It is the amount of replication lag you have agreed to buy with standby queries, and the queries are merely what gets thrown overboard when the budget runs out. max_standby_archive_delay is the same knob for WAL that arrives through restore_command instead of a walsender; I’ll treat the
max_slot_wal_keep_size decides who dies when a replica stops consuming WAL: the replica, or the primary. The default picks the primary.
That is not an exaggeration, and it is the whole argument for the parameter. A replication slot’s job is to keep the primary from recycling WAL its consumer hasn’t received yet, and a slot keeps that promise whether the
max_replication_slots is the length of an array in shared memory, and that is all it is. It doesn’t decide who may create a slot, how much WAL a slot may pin, or when an abandoned one gets cleaned up. It decides how many entries the array has; the array is allocated once, at startup; and so the only interesting property
A prepared transaction is a transaction that has been cut loose from its session. After PREPARE TRANSACTION 'some-gid', the session that started it has no transaction at all; the work it did, the locks it took, and its transaction ID go on existing by themselves, written to WAL, tracked in shared memory, restored after a crash, waiting for somebody
max_pred_locks_per_transaction has the naming problem of max_locks_per_transaction, and then one of its own. Like its namesake, it is a table size quoted per backend slot, not a limit on any transaction. Unlike its namesake, most of what its table holds at any given moment belongs to transactions that have already committed.
ClickHouse released WalShadow last week, and it does something very… brave: it replicates PostgreSQL into ClickHouse without using logical decoding at all. It reads the physical WAL stream, the same bytes a streaming replica gets, decodes heap records itself, and writes ClickHouse-native blocks. The latency and throughput numbers they published are good, and I believe with them.
Under SERIALIZABLE, PostgreSQL has to remember what every transaction read, and it has a fixed amount of shared memory to remember it in. These two parameters decide when it gives up remembering rows and remembers the page instead, and when it gives up on pages and remembers the whole table. Each step down in precision is paid for in