Transaction priorities
This page documents the preview version (v2.23). Preview includes features under active development and is for development and testing only. For production, use the stable version (v2024.1). To learn more, see Versioning.
When using the Fail-on-Conflict concurrency control policy, transactions are assigned priorities that help decide which transactions should be aborted in case of conflict.
There are two priority buckets, each having a priority range of reals in [0, 1] as follows:
-
High-priority
bucket: if the first statement in a transaction takes aFOR UPDATE/ FOR SHARE/ FOR NO KEY UPDATE
explicit row lock using SELECT, it will be assigned a priority from this bucket. -
Normal-priority
bucket: all other transactions are assigned a priority from this bucket.
Note that a transaction with any priority P1 from the high-priority bucket can abort a transaction with any priority P2 from the normal-priority bucket. For example, a transaction with priority 0.1 from the high-priority bucket can abort a transaction with priority 0.9 from the normal-priority bucket.
Priorities are randomly chosen from the applicable bucket. However, you can use the following two YSQL parameters to control the priority assigned to transactions in a specific session:
yb_transaction_priority_lower_bound
yb_transaction_priority_upper_bound
These parameters help set lower and upper bounds on the randomly-assigned priority that a transaction should receive from the applicable bucket. These parameters accept a value of real
datatype in the range [0, 1]. Also note that the same bounds apply to both buckets.
All single shard transactions have a priority of 1 in the normal-priority bucket.
The yb_get_current_transaction_priority
function can be used to fetch the transaction priority of the current active transaction. It outputs a pair <priority> (bucket)
, where <priority>
is of a real datatype between [0, 1] with 9 decimal units of precision, and <bucket>
is either Normal
or High
.
Note
As an exception, if a transaction is assigned the highest priority possible, that is, a priority of 1 in the high-priority bucket, the function returnshighest priority transaction
without any real value.
A transaction's priority is 0.000000000 (normal-priority transaction)
until a transaction is really started.
Examples
The following examples demonstrate how to set priorities for your transactions and get the current transaction priority.
-
Create a table and insert some data.
CREATE TABLE test (k INT PRIMARY KEY, v INT); INSERT INTO test VALUES (1, 1);
-
Set the lower and upper bound values for your transactions as follows:
SET yb_transaction_priority_lower_bound = 0.4; SET yb_transaction_priority_upper_bound = 0.6;
-
Create a transaction in the normal-priority bucket as follows:
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT yb_get_current_transaction_priority(); -- 0 due to an optimization which doesn't really start a real transaction internally unless a write occurs
yb_get_current_transaction_priority ------------------------------------------- 0.000000000 (Normal priority transaction) (1 row)
SELECT * FROM test;
k | v ---+--- 1 | 1 (1 row)
SELECT yb_get_current_transaction_priority(); -- still 0 due to the optimization which doesn't really start a real transaction internally unless a write occurs
yb_get_current_transaction_priority ------------------------------------------- 0.000000000 (Normal priority transaction) (1 row)
INSERT INTO test VALUES (2, '2'); -- perform a write which starts a real transaction SELECT yb_get_current_transaction_priority(); -- non-zero now
yb_get_current_transaction_priority ------------------------------------------- 0.537144608 (Normal priority transaction) (1 row)
COMMIT;
-
Create a transaction in the high-priority bucket as follows:
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT * FROM test WHERE k = 1 FOR UPDATE; -- starts a transaction in a high-priority bucket
k | v ---+--- 1 | 1 (1 row)
SELECT yb_get_current_transaction_priority();
yb_get_current_transaction_priority ----------------------------------------- 0.412004009 (High priority transaction) (1 row)
COMMIT;
-
Create a transaction with the highest priority
SET yb_transaction_priority_upper_bound = 1; SET yb_transaction_priority_lower_bound = 1; BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT * FROM test WHERE k = 1 FOR UPDATE;
k | v ---+--- 1 | 1 (1 row)
SELECT yb_get_current_transaction_priority();
yb_get_current_transaction_priority ------------------------------------- Highest priority transaction (1 row)
COMMIT;
Internal representation of priorities
Internally, both the normal and high-priority buckets are mapped to a uint64_t
space. The 64 bit range is used by the two priority buckets as follows:
-
Normal-priority bucket:
[yb::kRegularTxnLowerBound, yb::kRegularTxnUpperBound]
, that is, 0 touint32_t_max
-1 -
High-priority bucket:
[yb::kHighPriTxnLowerBound, yb::kHighPriTxnUpperBound]
, that is,uint32_t_max
touint64_t_max
For ease of use, the bounds are expressed as a [0, 1] real range for each bucket in the lower or upper bound YSQL parameters and the yb_get_current_transaction_priority
function. The [0, 1] real range map proportionally to the integer ranges for both buckets. In other words, the [0, 1] range in the normal-priority bucket maps to [0, uint32_t_max-1]
and the [0, 1] range in the high-priority bucket maps to [uint32_t_max, uint64_t_max]
.