Skip to main content
The DELETE deletes rows from a table.
To delete columns, see .

Required privileges

The user must have the DELETE and SELECT on the table.

Synopsis

delete syntax diagram

Parameters

ParameterDescription
common_table_exprSee .
table_nameThe name of the table that contains the rows you want to update.
AS table_alias_nameAn alias for the table name. When an alias is provided, it completely hides the actual table name.
USING table_refDelete rows based on a table , where table_ref specifies another table or tables to reference.
WHERE a_expra_expr must be an expression that returns Boolean values using columns (e.g., <column = <value>). Delete rows that return TRUE.

__Without a WHERE clause in your statement, DELETE removes all rows from the table. To delete all rows in a table, we recommend using instead of DELETE.
sort_clauseAn ORDER BY clause.

See for more details.
limit_clauseA LIMIT clause. See for more details.
RETURNING target_listReturn values based on rows deleted, where target_list can be specific column names from the table, * for all columns, or computations using .

To return nothing in the response, not even the number of rows updated, use RETURNING NOTHING.
ONLY ... *Supported for compatibility with PostgreSQL table inheritance syntax. This clause is a no-op, as CockroachDB does not currently support table inheritance.

Success responses

Successful DELETE statements return one of the following:
ResponseDescription
DELETE intint rows were deleted.

DELETE statements that do not delete any rows respond with DELETE 0. When RETURNING NOTHING is used, this information is not included in the response.
Retrieved tableIncluding the RETURNING clause retrieves the deleted rows, using the columns identified by the clause’s parameters.

See an example.

Disk space usage after deletes

Deleting a row does not immediately free up the disk space. This is due to the fact that CockroachDB retains the ability to query tables historically. If disk usage is a concern, the solution is to (TTL) for the zone by setting gc.ttlseconds to a lower value, which will cause garbage collection to clean up deleted objects (rows, tables) more frequently. For instructions on how to free up disk space as quickly as possible after dropping a table, see

Select performance on deleted rows

Queries that scan across tables that have lots of deleted rows will have to scan over deletions that have not yet been garbage collected. Certain database usage patterns that frequently scan over and delete lots of rows will want to reduce the values to clean up deleted rows more frequently.

Sorting the output of deletes

To sort the output of a DELETE statement, use:
For an example, see . For more information about ordering query results in general, see and .

Force index selection for deletes

By using the explicit index annotation (also known as “index hinting”), you can override CockroachDB’s index selection and use a specific for deleting rows of a named table.
Index selection can impact , but does not change the result of a query.
The syntax to force a specific index for a delete is:
This is equivalent to the longer expression:
To view how the index hint modifies the query plan that CockroachDB follows for deleting rows, use an statement. To see all indexes available on a table, use . For examples, see Delete with index hints. You can use the @primary alias to use the table’s primary key in your query if no secondary index explicitly named primary exists on that table.

Preserving DELETE performance over time

CockroachDB relies on to process concurrent requests while guaranteeing . As such, when you delete a row, it is not immediately removed from disk. The MVCC values for the row will remain until the garbage collection period defined by the variable in the applicable has passed. This means that with the default settings, each iteration of your DELETE statement must scan over all of the rows previously marked for deletion within . If you try to delete 10,000 rows 10 times within the GC TTL window, the 10th command will have to scan over the 90,000 rows previously marked for deletion. To preserve performance over iterative DELETE queries, we recommend taking one of the following approaches:
  • At each iteration, update the WHERE clause to filter only the rows that have not yet been marked for deletion. For an example, see .
  • At each iteration, first use a SELECT statement to return primary key values on rows that are not yet deleted. Rows marked for deletion will not be returned. Then, use a nested DELETE loop over a smaller batch size, filtering on the primary key values. For an example, see .
  • To iteratively delete rows in constant time, using a simple DELETE loop, you can and change gc.ttlseconds to a low value like 5 minutes (i.e., 300), and then run your DELETE statement once per GC interval.

Examples

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Delete rows using Primary Key/unique columns

Using columns with the or constraints to delete rows ensures your statement is unambiguous — no two rows contain the same column value, so it’s less likely to delete data unintentionally. In this example, code is our primary key and we want to delete the row where the code equals “about_stuff_city”. Because we’re positive no other rows have that value in the code column, there’s no risk of accidentally removing another row.

Delete rows using non-unique columns

Deleting rows using non-unique columns removes every row that returns TRUE for the WHERE clause’s a_expr. This can easily result in deleting data you didn’t intend to.
The example statement deleted four rows, which might be unexpected.

Delete rows using a table join

You can delete rows based on a table . Use the USING clause to specify another table. The following example deletes all codes from promo_codes that are present in user_promo_codes:

Return deleted rows

To see which rows your statement deleted, include the RETURNING clause to retrieve them using the columns you specify.

Use all columns

By specifying *, you retrieve all columns of the delete rows.

Use specific columns

To retrieve specific columns, name them in the RETURNING clause.

Change column labels

When RETURNING specific columns, you can change their labels using AS.

Sort and return deleted rows

To sort and return deleted rows, use a statement like the following:

Delete with index hints

Suppose you create a multi-column index on the users table with the name and city columns.
Now suppose you want to delete the two users named “Jon Snow”. You can use the command to see how the decides to perform the delete:
The output of the EXPLAIN statement shows that the optimizer scans the newly-created users_name_city_idx index when performing the delete. This makes sense, as you are performing a delete based on the name column. Now suppose that instead you want to perform a delete, but using the id column instead.
The optimizer still scans the newly-created users_name_city_idx index when performing the delete. Although scanning the table on this index could still be the most efficient, you may want to assess the performance difference between using users_name_city_idx and an index on the id column, as you are performing a delete with a filter on the id column. If you provide an index hint (i.e., force the index selection) to use the primary index on the column instead, the CockroachDB will scan the users table using the primary index, on city, and id.

See also