This tutorial shows you how to use Hibernate's @PartitionKey
annotation.
Partitioning a database table can be a solution to improve query performance if the system only needs to access certain rows. After creating the partitions, you have to make sure to use queries that utilize the partition key. For example, if a table is partitioned by a column, usually you need to include the column as a criteria in the queries. Otherwise, the database may need to perform scans on all partitions, making the partitioning useless.
Insert queries usually include the partition key. Therefore, the database should know to which partitions a row belongs to. However, for non-insert queries, the partition key should be added as a criteria, so that the database knows that it should only find matching rows on certain partition(s). If you use Hibernate version 6.2 or above, you can use the @PartitionKey
annotation.
Using @PartitionKey
Annotation
For example, we have a table named orders
and we want to partition it by the value of the date
column using a range partition. Below are the queries for creating the table along with the partitions. I use PostgreSQL for this tutorial. You may need to adjust the queries if you use another database.
CREATE TABLE orders (
id uuid NOT NULL,
amount numeric NOT NULL,
date date NOT NULL,
CONSTRAINT "pk_orders" PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
CREATE TABLE orders_2023_01 PARTITION OF orders
FOR VALUES FROM ('2023-01-01') TO ('2023-01-31');
CREATE TABLE orders_2023_02 PARTITION OF orders
FOR VALUES FROM ('2023-02-01') TO ('2023-02-28');
CREATE TABLE orders_2023_03 PARTITION OF orders
FOR VALUES FROM ('2023-03-01') TO ('2023-03-31');
Below is the entity class.
@Entity
@Table(name = "orders")
public class Order {
@Id
@UuidGenerator(style = UuidGenerator.Style.TIME)
private UUID id;
private BigDecimal amount;
private LocalDate date;
// Constructor, getters, setters
}
Let's say we want to fetch a row of the orders
table, increment the price by one, and update it to the database. For fetching, we can explicitly include the date
column as a criteria. However, for persisting the change to the database, usually we call the persist
or merge
method of Hibernate's EntityManager
.
String sql = "SELECT o FROM Order o WHERE o.id = :id AND o.date = :date";
Order order = (Order) this.entityManager.createQuery(sql)
.setParameter("id", id)
.setParameter("date", date)
.getSingleResult();
order.setAmount(order.getAmount().add(BigDecimal.ONE));
this.entityManager.merge(order);
Below is the generated query. Hibernate doesn't know the partition key. As a result, it doesn't include the date
column in the criteria. That causes the database to scan on all partitions.
update orders set amount=?,date=? where id=?
The solution is to add @PartitionKey
annotation to the date
field.
@Entity
@Table(name = "orders")
public class Order {
@Id
@UuidGenerator(style = UuidGenerator.Style.TIME)
private UUID id;
private BigDecimal amount;
@PartitionKey
private LocalDate date;
// Constructor, getters, setters
}
The @PartitionKey
annotation works by adding the annotated field as a criteria clause for UPDATE and DELETE queries generated by Hibernate. Below is the generated query after adding the annotation.
update orders set amount=?,date=? where id=? and date=?
The same also applies for delete queries. Here is the generated query for deleting a row.
delete from orders where id=? and date=?
You have to know that the annotation doesn't work for the following cases.
- SELECT queries, since we usually use explicit criteria for fetching rows.
- UPDATE/DELETE queries where the criteria is not generated by Hibernate or has to be set explicitly. For example, using a native query, Spring Data JPA's
Query
annotation, orCriteriaBuilder
.
Summary
The @PartitionKey
annotation can be useful for automatically adding the partition key as a criteria in UPDATE and DELETE queries. It may reduce the chance of missing partition key in the query criteria. Just make sure you have handled other queries not affected by the annotation.
You can also read about: