You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/features/load-balancer/manual-routing.md
+17-13Lines changed: 17 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,7 @@ Query comments are supported in all types of queries, including prepared stateme
23
23
24
24
Parameters are connection-specific settings that can be set on connection creation to configure database behavior. For example, this is how ORMs and web frameworks control settings like `application_name`, `statement_timeout` and many others.
25
25
26
-
The Postgres protocol doesn't have any restrictions on parameter names or values, and PgDog has access to them at connection creation.
26
+
The Postgres protocol doesn't have any restrictions on parameter names or values, and PgDog can intercept and handle them at any time.
27
27
28
28
The following two parameters allow you to control which database is used for all queries on a client connection:
29
29
@@ -34,16 +34,20 @@ The following two parameters allow you to control which database is used for all
34
34
35
35
The `pgdog.role` parameter accepts the following values:
36
36
37
-
| Parameter value | Behavior |
38
-
|-|-|
39
-
|`primary`| All queries are sent to the primary database. |
40
-
|`replica`| All queries are load balanced between replica databases, and possibly the primary if [`read_write_split`](../../configuration/pgdog.toml/general.md#read_write_split) is set to `include_primary` (default). |
37
+
| Parameter value | Behavior | Example |
38
+
|-|-|-|
39
+
|`primary`| All queries are sent to the primary database. |`SET pgdog.role TO "primary"`|
40
+
|`replica`| All queries are load balanced between replica databases, and possibly the primary if [`read_write_split`](../../configuration/pgdog.toml/general.md#read_write_split) is set to `include_primary` (default). |`SET pgdog.role TO "replica"`|
41
+
42
+
The `pgdog.shard` parameter accepts a shard number for any database specified in [`pgdog.toml`](../../configuration/pgdog.toml/databases.md), for example:
41
43
42
-
The `pgdog.shard` parameter accepts a shard number for any database specified in [`pgdog.toml`](../../configuration/pgdog.toml/databases.md).
44
+
```postgresql
45
+
SET pgdog.shard TO 1;
46
+
```
43
47
44
48
### Setting the parameters
45
49
46
-
Configuring parameters at connection creation is PostgreSQL driver-specific. Some of the common drivers and frameworks are shown below.
50
+
Configuring parameters can be done at connection creation, or by using the `SET` command. Below are examples of some of the common PostgreSQL drivers and web frameworks.
47
51
48
52
#### Database URL
49
53
@@ -114,19 +118,19 @@ Depending on the environment, the parameters may need to be URL-encoded, e.g., `
114
118
115
119
### Using `SET`
116
120
117
-
The PostgreSQL protocol supports configuring connection parameters using the `SET` statement. This also works for configuring both `pgdog.role` and `pgdog.shard`.
121
+
The PostgreSQL protocol supports changing connection parameters using the `SET` statement. By extension, this also works for changing `pgdog.role` and `pgdog.shard` settings.
118
122
119
-
For example, to make sure all subsequent queries to be sent to the primary, you can execute the following statement:
123
+
For example, to make sure all subsequent queries are sent to the primary, you can execute the following statement:
120
124
121
125
```postgresql
122
126
SET pgdog.role TO "primary";
123
127
```
124
128
125
-
The parameter is persisted on the connection until it's closed or the parameter is changed with another `SET` statement.
129
+
The parameter is persisted on the connection until it's closed or the value is changed with another `SET` statement. Before routing a query, the load balancer will check the value of this parameter, so setting it early on during connection creation ensures all transactions are executed on the right database.
126
130
127
131
#### Inside transactions
128
132
129
-
If you want to provide a transaction routing hint without affecting the rest of the connection, you can use`SET LOCAL`instead:
133
+
It's possible to set routing hints for the lifetime of a single transaction, by using the`SET LOCAL`command. This ensures the routing hint is used for one transaction only and doesn't affect the rest of the queries:
130
134
131
135
```postgresql
132
136
BEGIN;
@@ -136,7 +140,7 @@ SET LOCAL pgdog.role TO "primary";
136
140
In this example, all transaction statements (including the `BEGIN` statement) will be sent to the primary database. Whether the transaction is committed or reverted, the value of `pgdog.role` will be reset to its previous value.
137
141
138
142
!!! note "Statement ordering"
139
-
To make sure PgDog intercepts the routing hint early enough in the transaction flow, make sure to send all hints _before_ executing actual queries.
143
+
To make sure PgDog intercepts the routing hint early enough in the transaction flow, you need to send all hints _before_ executing actual queries.
140
144
141
145
The following flow, for example, _will not_ work:
142
146
@@ -153,7 +157,7 @@ In this example, all transaction statements (including the `BEGIN` statement) wi
153
157
154
158
In certain situations, the overhead of parsing queries may be too high, e.g., when your application can't use prepared statements.
155
159
156
-
If you've configured the desired database role (and/or shard) for each of your application connections, you can disable the query parser in [pgdog.toml](../../configuration/pgdog.toml/general.md#query_parser):
160
+
If you've configured the desired database role (and/or shard) for each of your application connections, you can disable the query parser in [`pgdog.toml`](../../configuration/pgdog.toml/general.md#query_parser):
Copy file name to clipboardExpand all lines: docs/features/load-balancer/transactions.md
+21-16Lines changed: 21 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ icon: material/swap-horizontal
6
6
7
7
PgDog's load balancer is [transaction-aware](../transaction-mode.md) and will ensure that all statements inside a transaction are sent to the same PostgreSQL connection on just one database.
8
8
9
-
To make sure all queries inside a transaction succeed, PgDog will route all manually started transactions to the **primary** database.
9
+
To make sure all queries inside a transaction succeed, PgDog will route all manually started transactions to the primary database.
PgDog processes queries immediately upon receiving them, and since transactions can contain multiple statements, it isn't possible to determine whether one of the statements won't write to the database.
21
+
PgDog executes queries immediately upon receiving them, and since transactions can contain multiple statements, it isn't possible to determine in advance what the statements will do.
22
22
23
-
Therefore, it is more reliable to send the entire transaction to the primary database.
23
+
Therefore, it is more reliable to send the entire transaction to the primary, which can handle all types of queries.
24
24
25
25
### Read-only transactions
26
26
27
-
The PostgreSQL query language allows you to declare a transaction as read-only, which prevents it from writing data to the database. PgDog can take advantage of this property and will send such transactions to a replica database.
27
+
The PostgreSQL query language allows you to declare a transaction as read-only. This property prevents it from writing data, even if a databasecan accept writes.
28
28
29
-
Read-only transactions are started with the `BEGIN READ ONLY` command, for example:
29
+
PgDog takes advantage of this property and will send such transactions to a replica. Read-only transactions are started with the `BEGIN READ ONLY` command, for example:
30
30
31
31
```postgresql
32
32
BEGIN READ ONLY;
33
33
SELECT * FROM users WHERE id = $1;
34
34
COMMIT;
35
35
```
36
36
37
-
Read-only transactions are useful when queries need a consistent view of the database. Some Postgres database drivers allow this option to be set in the code, for example:
37
+
In addition to forcing all statements to a replica, read-only transactions are useful when queries need a consistent view of the database. Most Postgres client drivers allow this option to be set in the code, for example:
38
38
39
-
=== "pgx (go)"
39
+
=== "pgx (Go)"
40
40
```go
41
41
tx, err := conn.BeginTx(ctx, pgx.TxOptions{
42
42
AccessMode: pgx.ReadOnly,
43
43
})
44
44
```
45
-
=== "Sequelize (node)"
45
+
=== "Sequelize (Node)"
46
46
```javascript
47
47
const tx = await sequelize.transaction({
48
48
readOnly: true,
49
49
});
50
50
```
51
-
=== "SQLAlchemy (python)"
52
-
Add `postgresql_readonly=True` to [execution options](https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.Engine.execution_options), like so:
While transactions are used to atomically change multiple tables, they can also be used to manually route `SELECT` queries to the primary database. For example:
59
+
Since PgDog sends all manual transactions to the primary, they can also be used to send `SELECT` queries to the primary as well.
60
+
61
+
For example:
61
62
62
63
```postgresql
63
64
BEGIN;
64
65
SELECT * FROM users WHERE id = $1;
65
66
COMMIT;
66
67
```
67
68
68
-
This is useful when the data in the table(s) has been recently updated and you want to avoid errors caused by replication lag. This often manifests as "record not-found"-style errors, for example:
69
+
This avoids having to write additional code to handle replication lag, which is useful when the data in the table(s) has been recently updated and you want to avoid fetching stale or nonexistent rows.
69
70
70
-
```
71
-
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=9999):
72
-
```
73
71
74
-
While sending read queries to the primary adds load, it is often necessary in real-time systems that are not equipped to handle replication delays.
72
+
!!! note "Example"
73
+
If you're using Rails/ActiveRecord, these types of errors sometimes manifest like this:
74
+
75
+
```
76
+
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=9999):
77
+
```
78
+
79
+
While sending read queries to the primary adds additional load, it is often necessary in real-time systems that are not equipped to handle replication delays.
0 commit comments