Skip to content

Commit

Permalink
Update based on reviewer feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
rmloveland committed Dec 18, 2019
1 parent fac6eeb commit b7c31ee
Showing 1 changed file with 17 additions and 13 deletions.
30 changes: 17 additions & 13 deletions v20.1/selection-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,14 +349,18 @@ The general pattern for keyset pagination queries is:

{% include copy-clipboard.html %}
~~~ sql
SELECT * FROM t
SELECT * FROM t AS OF SYSTEM TIME ${time}
WHERE key > ${value}
ORDER BY key
LIMIT ${amount}
~~~

This is faster than using `LIMIT`/`OFFSET` because, instead of doing a full table scan up to the value of the `OFFSET`, a keyset pagination query looks at a fixed-size set of records for each iteration. This can be done quickly provided that the key used in the `WHERE` clause to implement the pagination is [indexed](indexes.html#best-practices) and [unique](unique.html). A [primary key](primary-key.html) meets both of these criteria.

{{site.data.alerts.callout_info}}
CockroachDB does not have cursors. To support a cursor-like use case, namely "operate on a snapshot of the database at the moment the cursor is opened", use the [`AS OF SYSTEM TIME`](as-of-system-time.html) clause as shown in the examples below.
{{site.data.alerts.end}}

#### Pagination example

The examples in this section use the [employees data set](https://github.com/datacharmer/test_db), which you can load into CockroachDB as follows:
Expand All @@ -368,11 +372,11 @@ USE employees;
IMPORT PGDUMP 'https://s3-us-west-1.amazonaws.com/cockroachdb-movr/datasets/employees-db/pg_dump/employees-full.sql.gz';
~~~

To get the first page of results using keyset pagination, run:
To get the first page of results using keyset pagination, run the statement below.

{% include copy-clipboard.html %}
~~~ sql
SELECT * FROM employees WHERE emp_no > 10000 LIMIT 25;
SELECT * FROM employees AS OF SYSTEM TIME '-1m' WHERE emp_no > 10000 ORDER BY emp_no LIMIT 25;
~~~

~~~
Expand All @@ -389,14 +393,18 @@ Time: 1.31ms
~~~

{{site.data.alerts.callout_success}}
If you don't know what the minimum value of the key is, either `SELECT min(key) FROM table` or use a known minimum value for the key's data type.
When writing your own queries of this type, use a known minimum value for the key's data type. If you don't know what the minimum value of the key is, you can use `SELECT min(key) FROM table`.
{{site.data.alerts.end}}

{{site.data.alerts.callout_info}}
We use [`AS OF SYSTEM TIME`](as-of-system-time.html) in these examples to ensure that we are operating on a consistent snapshot of the database as of the specified timestamp. This reduces the chance that there will be any concurrent updates to the data the query is accessing, and thus no missing or duplicated rows during the pagination. It also reduces the risk of [transaction retries](transactions.html#client-side-intervention) due to concurrent data access. The value of `-1m` passed to `AS OF SYSTEM TIME` may need to be updated depending on your application's data access patterns.
{{site.data.alerts.end}}

To get the second page of results, run:

{% include copy-clipboard.html %}
~~~ sql
SELECT * FROM employees WHERE emp_no > 10025 LIMIT 25;
SELECT * FROM employees AS OF SYSTEM TIME '-1m' WHERE emp_no > 10025 ORDER BY emp_no LIMIT 25;
~~~

~~~
Expand All @@ -412,11 +420,11 @@ SELECT * FROM employees WHERE emp_no > 10025 LIMIT 25;
Time: 1.473ms
~~~

To get an arbitrary page of results showing employees whose IDs (`emp_no`) are in a much higher range, try the following query. Note that it takes about the same amount of time to run as the previous queries.
To get an arbitrary page of results showing employees whose IDs (`emp_no`) are in a much higher range, run the following query. Note that it takes about the same amount of time to run as the previous queries.

{% include copy-clipboard.html %}
~~~ sql
SELECT * FROM employees WHERE emp_no > 300025 LIMIT 25;
SELECT * FROM employees AS OF SYSTEM TIME '-1m' WHERE emp_no > 300025 ORDER BY emp_no LIMIT 25;
~~~

~~~
Expand All @@ -436,7 +444,7 @@ Compare the execution speed of the previous keyset pagination queries with the q

{% include copy-clipboard.html %}
~~~ sql
SELECT * FROM employees LIMIT 25 OFFSET 200024;
SELECT * FROM employees AS OF SYSTEM TIME '-1m' LIMIT 25 OFFSET 200024;
~~~

~~~
Expand Down Expand Up @@ -478,7 +486,7 @@ Meanwhile, the keyset pagination queries are looking at a much smaller range of

{% include copy-clipboard.html %}
~~~ sql
EXPLAIN SELECT * FROM employees WHERE emp_no > 300025 LIMIT 25;
EXPLAIN SELECT * FROM employees WHERE emp_no > 300025 ORDER BY emp_no LIMIT 25;
~~~

~~~
Expand All @@ -496,10 +504,6 @@ EXPLAIN SELECT * FROM employees WHERE emp_no > 300025 LIMIT 25;
Using a sequential (i.e., non-[UUID](uuid.html)) primary key creates hot spots in the database for write-heavy workloads, since concurrent [`INSERT`](insert.html)s to the table will attempt to write to the same (or nearby) underlying [ranges](architecture/overview.html#architecture-range). This can be mitigated by designing your schema with [multi-column primary keys which include a monotonically increasing column](performance-best-practices-overview.html#use-multi-column-primary-keys).
{{site.data.alerts.end}}

{{site.data.alerts.callout_info}}
CockroachDB does not implement cursors. For a scale-out system like CockroachDB, using a cursor would not be recommended for the same reason that paginating with `LIMIT`/`OFFSET` is not recommended: it forces the server to keep track of state, which means the pagination queries don't scale well.
{{site.data.alerts.end}}

## Composability

[Selection clauses](#selection-clauses) are defined in the context of selection queries. [Table expressions](table-expressions.html) are defined in the context of the `FROM` sub-clause of [`SELECT`](select-clause.html). Nevertheless, they can be integrated with one another to form more complex queries or statements.
Expand Down

0 comments on commit b7c31ee

Please sign in to comment.