Batch-delete “expired” data
CockroachDB has support for Time to Live (“TTL”) expiration on table rows, also known as Row-Level TTL. Row-Level TTL is a mechanism whereby rows from a table are considered “expired” and can be automatically deleted once those rows have been stored longer than a specified expiration time. For more information, see .Manually delete data using batches
This section provides guidance on batch deleting with theDELETE query filter on an indexed column and on a non-indexed column. Filtering on an indexed column is both simpler to implement and more efficient, but adding an index to a table can slow down insertions to the table and may cause bottlenecks. Queries that filter on a non-indexed column must perform at least one full-table scan, a process that takes time proportional to the size of the entire table.
Exercise caution when batch deleting rows from tables with foreign key constraints and explicit . To preserve
DELETE performance on tables with foreign key actions, we recommend using smaller batch sizes, as additional rows updated or deleted due to ON DELETE actions can make batch loops significantly slower.Before you begin
Before reading this page, do the following:- or .
- .
- .
- that you now want to delete. For the example on this page, we load a cluster with the and data from .
Batch delete on an indexed column
For high-performance batch deletes, we recommending filtering theDELETE query on an .
Having an indexed filtering column can make delete operations faster, but it might lead to bottlenecks in execution, especially if the filtering column is a . To reduce bottlenecks, we recommend using a .
DELETE query. When writing this DELETE query:
- Use a
WHEREclause to filter on a column that identifies the unwanted rows. If the filtering column is not the primary key, the column should have . Note that if the filtering column is not already indexed, it is not beneficial to add an index just to speed up batch deletes. Instead, consider batch deleting on non-indexed columns. - To ensure that rows are efficiently scanned in the
DELETEquery, add an clause on the filtering column. - Use a clause to limit the number of rows to the desired batch size. To determine the optimal batch size, try out different batch sizes (1,000 rows, 10,000 rows, 100,000 rows, etc.) and monitor the change in performance.
- Add a
RETURNINGclause to the end of the query that returns the filtering column values of the deleted rows. Then, using the values of the deleted rows, update the filter to match only the subset of remaining rows to delete. This narrows each query’s scan to the fewest rows possible, and . This pattern assumes that no new rows are generated that match on theDELETEfilter during the time that it takes to perform the delete.
Examples
Choose the language for the example code.- Python (psycopg2)
- Java (JDBC)
- C# (Npgsql)
For example, suppose that you want to delete all rows in the
new_order table where no_w_id is less than 5, in batches of 5,000 rows. To do this, you can write a query that loops over batches of 5,000 rows, following the DELETE query guidance provided above. Note that in this case, no_w_id is the first column in the primary index, and, as a result, you do not need to create a secondary index on the column.In Python using the psycopg2 driver, the script would look similar to the following:no_w_id <= 4 are deleted. Note that at each iteration, the filter is updated to match a narrower subset of rows.
Batch delete on a non-indexed column
If you cannot index the column that identifies the unwanted rows, we recommend defining the batch loop to execute separate read and write operations at each iteration:-
Execute a that returns the primary key values for the rows that you want to delete. When writing the
SELECTquery:- Use a
WHEREclause that filters on the column identifying the rows. - If you need to avoid you can use an at the end of the selection subquery, or run the selection query in a separate, read-only transaction with . If you add an
AS OF SYSTEM TIMEclause, make sure your selection query to get the batches of rows is run outside of the window of theAS OF SYSTEM TIMEclause. That is, if you useAS OF SYSTEM TIME '-5s'to find the rows to delete, you should wait at least 5 seconds before rerunning the select query. Otherwise you will retrieve rows that have already been deleted. - Use a clause to limit the number of rows queried to a subset of the rows that you want to delete. To determine the optimal
SELECTbatch size, try out different sizes (10,000 rows, 100,000 rows, 1,000,000 rows, etc.), and monitor the change in performance. Note that thisSELECTbatch size can be much larger than the batch size of rows that are deleted in the subsequentDELETEquery. - To ensure that rows are efficiently scanned in the subsequent
DELETEquery, include an clause on the primary key.
- Use a
-
Write a nested
DELETEloop over the primary key values returned by theSELECTquery, in batches smaller than the initialSELECTbatch size. To determine the optimalDELETEbatch size, try out different sizes (1,000 rows, 10,000 rows, 100,000 rows, etc.), and monitor the change in performance. Where possible, we recommend executing eachDELETEin a separate transaction.
history table that are older than a month. You can create a script that loops over the data and deletes unwanted rows in batches, following the query guidance provided above.
Examples
Choose the language for the example code.- Python (psycopg2)
- Java (JDBC)
- C# (Npgsql)
In Python, the script would look similar to the following:
DELETE loop, a batch of rows is deleted. After the nested DELETE loop deletes all of the rows from the initial selection query, a time delay ensures that the next selection query reads historical data from the table after the last iteration’s DELETE final delete.
CockroachDB records the timestamp of each row created in a table in the
crdb_internal_mvcc_timestamp metadata column. In the absence of an explicit timestamp column in your table, you can use crdb_internal_mvcc_timestamp to filter expired data.crdb_internal_mvcc_timestamp cannot be indexed. If you plan to use crdb_internal_mvcc_timestamp as a filter for large deletes, you must follow the non-indexed column pattern.Exercise caution when using crdb_internal_mvcc_timestamp in production, as the column is subject to change without prior notice in new releases of CockroachDB. Instead, we recommend creating a column with an to avoid any conflicts due to internal changes to crdb_internal_mvcc_timestamp.Delete all of the rows in a table
To delete all of the rows in a table, use a . For example, to delete all rows in thenew_order table, execute the following SQL statement:
Examples
Choose the language for the example code.- Python (psycopg2)
- Java (JDBC)
- C# (Npgsql)
For example, in Python, using the
psycopg2 client driver:
