# `TableReader` Data Aggregator, `TableFullScan` Operator and `Selection` Filter

+ **`TableReader`** aggregates the data retrieved from the table using the underlying operators
+ **`TableFullScan`** scans the entire table
+ **`Selection`** represents a filter is applied on the data read by the underlying operator, which **may** imply a sub-optimal plan
+ In case with the high selectivity and the table contains a lot of rows, **`TableFullScan`** is inefficient

```
tidb> EXPLAIN SELECT * FROM employees WHERE first_name LIKE 'P%';
+--------------------+-----------+-----------+-----------------+------------------------------------------------+
| id                 | estRows   | task      | access object   | operator info                                  |
+--------------------+-----------+-----------+-----------------+------------------------------------------------+
| TableReader_7      | 10311.54  | root      |                 | data:Selection_6                               |
| └─Selection_6      | 10311.54  | cop[tikv] |                 | like(employees.employees.first_name, "P%", 92) |
|  └─~!@TableFullScan_5 | 300024.00 | cop[tikv] | table:employees@!~ | keep order:false                               |
+--------------------+-----------+-----------+-----------------+------------------------------------------------+
3 rows in set (0.00 sec)
```

------------------------------------------------------------------------------
The execution plan of the example SQL statement involves the following steps: The first child step, `TableFullScan_5`, scans all rows of the `employees` table on the TiKV nodes. Next, the filtered data is processed using the TiKV coprocessor, represented by `Selection_6`. Finally, the filtered data is aggregated from various TiKV nodes and returned to the TiDB Server, as indicated by `TableReader_7`, which shows that the query is executed through a table scan without using an index.

Although the SQL statement includes the `WHERE` predicate `WHERE first_name LIKE 'P%'`, which might suggest that an index could be used, however the optimizer determines that the index would not be advantageous. The predicate `first_name LIKE 'P%'` matches all names starting with the letter `'P'`, potentially resulting in a large result set, the optimizer chooses a full table scan over using the index.

From this perspective, full table scans aren't necessarily detrimental. Consider a table with 10 million rows where using an index would filter out 5 million rows. If an index were used, it would first scan the index in TiKV with `IndexRangeScan` to retrieve the key values for the table's key-value pairs. The TiDB Server would then use these key values to fetch the corresponding values from TiKV. However, if the key values are widely dispersed across various regions and TiKV nodes, the worst-case scenario could involve reading each row individually, resulting in nearly 5 million complete read operations. For example, if the I/O bandwidth can handle 1 GB of data at once but is limited to reading only 1 row at a time, this approach becomes inefficient.

In contrast, a full table scan would involve each TiKV node filtering data within its respective regions from the table with 10 million rows, then returning the filtered rows to the TiDB Server, which in turn delivers the results to the user. This approach has two key advantages:

1. Parallelized Scanning: Data is distributed across multiple TiKV nodes, enabling parallel processing and leveraging the benefits of a distributed database.
2. Efficient I/O Utilization: Since the key values within each region in TiKV are contiguous, each I/O read can efficiently utilize available bandwidth by fetching multiple rows of data at once (e.g., 1 GB of data), which is more efficient than index reads that may only retrieve one or a few rows per I/O operation.

Therefore, in performance optimization, it is essential to consider factors such as the distribution of indexed columns and the size of the result set. Simple decisions to apply indexes without thorough evaluation can lead to suboptimal performance.

Lastly, `Selection` represents a filtering operation. However, filtering isn't always inefficient. For example, in a particular execution plan, an index is used to perform a range scan on 10 rows out of 1 billion. A subsequent condition further narrows the selection to 4 rows from those 10, demonstrating the effective use of the `Selection` operation. Selectivity is the keys to justify `Selection` operation.