> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ditto.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Access paths

> Collection access paths produced by the query planner.

## Access paths

### Ditto Server

Primary access paths are determined internally in the subscription server with DQL only supplying relevant predicates.  The one current exception is the `countScan` (see below).  The predicates and details of plan type selection can be seen in the `scan` operator in the [EXPLAIN](/dql/explain) output (plan) for a statement.

### Ditto SDK

With the event of indexing the Query planner now has multiple options when deciding how to execute a query.  The details of the access path chosen can be seen in the [EXPLAIN](/dql/explain) output (plan) for the statement.

The access path selected is determined by the statement's filters, ordering and [directives](/dql/indexing#directive-reference).

### Types of access paths

<Note>
  Index, intersect and union scans may be combined into a hierarchy.
</Note>

#### Collection scan

A collection scan retrieves all the (complete) documents in a collection sequentially without any guarantee of order.  A collection scan is the fall-back when a statement can't be implemented with another access path.  It can be forced with an empty or null index directive.

Example:

```text theme={null}
    {
      "#operator": "scan",
      "collection": "test",
      "datasource": "default",
      "descriptor": {
        "path": {
          "_id": "query_details",
          "full_scan": {}
        }
      }
    }
```

<Note>
  If any portion of a query is to be served by a collection scan then no other scan will be used.
</Note>

#### Index scan

An index scan is a scan of an index on the collection which returns document IDs matching the noted spans.  (A "span" is a filter for an index key and indicates a range of values to return.)  An index scan is picked based on filtering and possibly ordering present in the statement.  A specific index can be forced if it still applies to the statement via the index [directive](/dql/indexing#directive-reference).

Example (filter: `WHERE field1 = "test filter"`):

```text theme={null}
    {
      "#operator": "indexScan",
      "collection": "test",
      "datasource": "default",
      "desc": {
        "index": "ix1",
        "spans": [
          {
            "index_key": {
              "direction": "asc",
              "include_missing": true,
              "key": [
                "field1"
              ]
            },
            "range": {
              "high": {
                "included": true,
                "value": "test filter"
              },
              "low": {
                "included": true,
                "value": "test filter"
              }
            }
          }
        ]
      }
    }
```

#### Intersect scan

An intersect scan combines index scans and union scans and returns only document IDs produced by all its children (logical AND).  It is used support multiple filters on different indexed fields in a statement.  It cannot be forced but the maximum number of children is controlled by the intersects [directive](/dql/indexing#directive-reference).

Example (filter: `WHERE field1 = "test filter" AND field2 > 0`:

```text theme={null}
    {
      "#operator": "intersectScan",
      "children": [
        {
          "#operator": "indexScan",
          "collection": "test",
          "datasource": "default",
          "desc": {
            "index": "ix1",
   ...
        },
        {
          "#operator": "indexScan",
          "collection": "test",
          "datasource": "default",
          "desc": {
            "index": "ix2",
    ...
        }
      ]
    }
```

#### Union scan

A union scan combines index scans and intersect scans and returns only unique document IDs across all its children (logical OR).  It is used to support multiple ranges of a single index and for multiple optional condition sets (OR) in the statement.  It cannot be forced.

`IN` filters with a list length to the lower limit of the number of remaining scans or maximum in-list-element directive, *may* be effected with a union scan.

Example (filter: `WHERE field1 = "test filter" OR field2 <= 123`:

```text theme={null}
    {
      "#operator": "unionScan",
      "children": [
        {
          "#operator": "indexScan",
          "collection": "test",
          "datasource": "default",
          "desc": {
          "index": "ix1",
    ...
        }
        },
        {
          "#operator": "indexScan",
          "collection": "test",
          "datasource": "default",
          "desc": {
            "index": "ix2",
    ...
        }
      ]
    }
```

## Fetching documents

When a collection scan is not the access path and additional document fields are needed, a `fetch` operator is used to retrieve full documents based on the document IDs produced earlier in the plan.  A collection scan retrieves the documents itself so this step is not necessary.

Example:

```text theme={null}
    {
      "#operator": "fetch",
      "collection": "test",
      "datasource": "default"
    }
```

## See Also

* [Operator Expressions](/dql/operator-expressions#array-and-object-search-expressions) - `ANY`/`EVERY` array and object search expressions, `ARRAY`/`OBJECT` transformation expressions
* [IDs, Paths, Strings, and Keywords](/dql/ids-paths-strings-keywords#attachment-path-expressions) - Attachment path expressions
