---
title: "TABLE SCAN - OceanBase 数据库 V4.3.5 | OceanBase 文档中心"
description: TABLE SCAN TABLE SCAN 算子是存储层和 SQL 层的接口，用于展示优化器选择哪个索引（或主表）来访问数据。 从 OceanBase 数据库 V4.1.0 版本开始，对于普通索引和全局索引，索引回表的逻辑是封装在 TABLE SCAN 算子中的；在执行计划展示时，会有 is_index_back 标…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 4.3.5 LTS

# TABLE SCAN

更新时间：2026-07-19 16:40:56

[编辑](https://github.com/oceanbase/oceanbase-doc/edit/V4.3.5/zh-CN/700.reference/1000.performance-tuning-guide/500.sql-optimization/200.sql-execution-plan/400.execution-plan-operator/100.table-scan.md)  

`TABLE SCAN` 算子是存储层和 SQL 层的接口，用于展示优化器选择哪个索引（或主表）来访问数据。

从 OceanBase 数据库 V4.1.0 版本开始，对于普通索引和全局索引，索引回表的逻辑是封装在 `TABLE SCAN` 算子中的；在执行计划展示时，会有 `is_index_back` 标识算子是否需要回表，以及 `is_global_index` 标识算子是否是扫描全局索引。

## TABLE SCAN 算子类型

`TABLE SCAN` 代表了从表中读取数据的一系列基本操作，根据不同的查询条件和数据访问路径（是否使用索引、使用何种索引以及扫描方式），`TABLE SCAN` 在 `OPERATOR` 中展示类型如下：

| 算子类型 | 特性说明 | 返回行数 | 触发条件 |
| --- | --- | --- | --- |
| TABLE GET | 主键精确匹配，单行访问。基于主键等值条件定位到唯一或不存在的数据行。 | 0 行或 1 行。 | WHERE 条件包含主键的等值查询，如 `WHERE primary_key = ?`。 |
| TABLE RANGE SCAN | 基于索引键值的有序性，扫描满足一个或多个范围条件（`range_cond`）的数据区间。 | 0 行或多行，取决于 `range_cond` 的筛选率。 | `WHERE` 条件包含索引列的范围查询，如 `WHERE indexed_column > ?`。 |
| DISTRIBUTED TABLE RANGE SCAN | 对全局索引或分布式表进行跨分区扫描。分布式连续范围：在全局索引的多个分区上执行区间扫描。 | 0 行或多行，取决于所有分区内匹配的行数。 | 对分区表的全局索引进行查询，且查询条件无法将数据定位到单一分区时。 |
| TABLE SKIP SCAN | 跳跃扫描联合索引的后缀列。多段跳跃范围：先枚举索引前缀列的不同值，再对每个值在后缀列上扫描指定区间。 | 0 行或多行，取决于前缀列的不同值数量及各段扫描结果。 | 查询条件仅包含联合索引的非最左列，且查询的所有列均在该索引中（覆盖索引扫描），如 `WHERE index(col1, col2)` 且条件为 `col2 = ?`。 |
| TABLE FULL SCAN | 全表扫描。无范围限制，扫描全部数据。 | 所有行。 | 无有效索引或强制全表扫描。 |

## TABLE GET

`TABLE GET` 直接使用主键（Primary Key）进行精确匹配定位，每次执行只返回 0 行或 1 行数据。通常用于 `WHERE` 条件中包含主键等值查询的场景。

### TABLE GET 示例

1. 创建表 `tbl1`，定义列 `col1` 为主键。

   ```shell
   obclient> CREATE TABLE tbl1(col1 INT PRIMARY KEY, col2 INT, col3 INT, col4 INT);

   ```
 2. Q1：查看含 `TABLE GET` 类型的执行计划。

   ```shell
   obclient> EXPLAIN SELECT * FROM tbl1 WHERE col1 = 1;

   ```

   返回结果如下：

   ```shell
   +------------------------------------------------------------------------------------------+
   | Query Plan                                                                               |
   +------------------------------------------------------------------------------------------+
   | =========================================                                                |
   | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|                                                |
   | -----------------------------------------                                                |
   | |0 |TABLE GET|TBL1|1       |5           |                                                |
   | =========================================                                                |
   | Outputs & filters:                                                                       |
   | -------------------------------------                                                    |
   |   0 - output([TBL1.COL1], [TBL1.COL2], [TBL1.COL3], [TBL1.COL4]), filter(nil), rowset=16 |
   |       access([TBL1.COL1], [TBL1.COL2], [TBL1.COL3], [TBL1.COL4]), partitions(p0)         |
   |       is_index_back=false, is_global_index=false,                                        |
   |       range_key([TBL1.COL1]), range[1 ; 1],                                              |
   |       range_cond([TBL1.COL1 = 1])                                                        |
   +------------------------------------------------------------------------------------------+
   12 rows in set

   ```

在 Q1 查询结果中，算子类型（`OPERATOR`）使用的是 `TABLE GET`。执行计划 `Outputs & filters` 部分各个参数的详细解释如下：

| 信息名称 | 含义 | 示例说明 |
| --- | --- | --- |
| output | 该算子最终输出的列列表。 | `output([TBL1.COL1], [TBL1.COL2], [TBL1.COL3], [TBL1.COL4])` 表示查询将返回表 `tbl1` 中的 `col1`、`col2`、`col3`、`col4` 四列。 |
| filter | 该算子需要应用的过滤条件（谓词）。 | `filter(nil)` 表示没有额外的过滤条件，数据在通过 `range_cond` 定位后直接输出。 |
| rowset | 当前算子的向量化大小。 | `rowset=16` 表示当前算子的向量化大小为 16。 |
| access | 该算子为了完成计算所需要访问的列列表。其顺序可能与 `output` 不同，通常与索引结构相关。 | `access([TBL1.COL1], [TBL1.COL2], [TBL1.COL3], [TBL1.COL4])` 表示需要读取 `col1`、`col2`、`col3`、`col4` 这些列的值。 |
| partitions | 查询需要扫描的分区。 | `partitions(p0)` 表示本次查询只访问了名为 `p0` 的分区。   #### 说明    如果表是非分区表，那么整个表就是一个单独的分区 `p0`。 |
| is_index_back | 表示该算子是否需要 “回表” 操作。即是否需要在通过索引定位到主键后，再回到主表中去获取其他列的数据。 | `is_index_back=false` 表示不需要回表。在 Q1 查询中，因为使用了主键（`col1`）进行精确查找，且需要所有列，而主键索引（主表）本身包含了全部列数据，所以不需要回表。 |
| is_global_index | 表示本次查询是否使用了全局索引。 | `is_global_index=false` 表示没有使用全局索引。 |
| range_key | 表示扫描范围的行键（`rowkey` 列），决定了数据的排序方式。对于表（主表）而言，行键就是主键；对于索引，行键就是索引键。 | `range_key([TBL1.COL1])` 表示扫描范围由主键列 `col1` 决定。 |
| range | 索引扫描的起止范围，格式为 `(起始键值 ; 结束键值)`。 | `range[1 ; 1]` 表示扫描范围是从 `col1=1` 到 `col1=1`，这是一个精确的点查询，而非范围扫描。 |
| range_cond | 决定上述扫描范围 (`range`) 的查询条件。 | `range_cond([TBL1.COL1 = 1])` 直接对应了 SQL 语句中的 `WHERE col1 = 1`，优化器根据这个条件推导出了 `range[1 ; 1]`。 |

## TABLE RANGE SCAN

`TABLE RANGE SCAN` 属于范围扫描，会根据给定的查询条件（范围谓词）扫描索引或主表的一段连续范围，返回 0 行或多行数据。该类型适用于带有 `>`、`<`、`BETWEEN`、`LIKE` 前缀匹配等范围条件的查询。

### TABLE RANGE SCAN 示例

1. 创建表 `tbl2`，定义列 `col1` 为主键。

   ```shell
   obclient> CREATE TABLE tbl2(col1 INT PRIMARY KEY, col2 INT, col3 INT, col4 INT);

   ```
 2. 在表 `tbl2` 上基于列 `col2` 和 `col3` 创建索引 `idx_tbl2`。

   ```shell
   obclient> CREATE INDEX idx_tbl2 ON tbl2(col2, col3);

   ```
 3. Q2：查看含 `TABLE RANGE SCAN` 类型的执行计划。

   ```shell
   obclient> EXPLAIN SELECT * FROM tbl2
       WHERE col2 < 1
       AND col3 < 1
       AND col4 < 1;

   ```

   返回结果如下：

   ```shell
   +-----------------------------------------------------------------------------------------------------------------------+
   | Query Plan                                                                                                            |
   +-----------------------------------------------------------------------------------------------------------------------+
   | ==========================================================                                                            |
   | |ID|OPERATOR        |NAME          |EST.ROWS|EST.TIME(us)|                                                            |
   | ----------------------------------------------------------                                                            |
   | |0 |TABLE RANGE SCAN|TBL2(IDX_TBL2)|1       |5           |                                                            |
   | ==========================================================                                                            |
   | Outputs & filters:                                                                                                    |
   | -------------------------------------                                                                                 |
   |   0 - output([TBL2.COL1], [TBL2.COL2], [TBL2.COL3], [TBL2.COL4]), filter([TBL2.COL3 < 1], [TBL2.COL4 < 1]), rowset=16 |
   |       access([TBL2.COL1], [TBL2.COL2], [TBL2.COL3], [TBL2.COL4]), partitions(p0)                                      |
   |       is_index_back=true, is_global_index=false, filter_before_indexback[true,false],                                 |
   |       range_key([TBL2.COL2], [TBL2.COL3], [TBL2.COL1]), range(MIN,MIN,MIN ; 1,MIN,MIN),                               |
   |       range_cond([TBL2.COL2 < 1])                                                                                     |
   +-----------------------------------------------------------------------------------------------------------------------+
   12 rows in set

   ```

在 Q2 查询结果中，算子类型（`OPERATOR`）使用的是 `TABLE RANGE SCAN`。执行计划 `Outputs & filters` 部分各个参数的详细解释如下：

| 信息名称 | 含义 | 示例说明 |
| --- | --- | --- |
| output | 该算子最终输出的列列表。 | `output([TBL2.COL1], [TBL2.COL2], [TBL2.COL3], [TBL2.COL4])` 表示查询将返回表 `tbl2` 中的 `col1`、`col2`、`col3`、`col4` 四列。 |
| filter | 该算子需要应用的过滤条件（谓词）。 | `filter([TBL2.COL3 < 1], [TBL2.COL4 < 1])` 表示有两道过滤：`col3 < 1` 和 `col4 < 1`。`WHERE` 子句中的 `col2 < 1` 未被列在此处，因为它被用于确定扫描范围（`range_cond`）。 |
| rowset | 当前算子的向量化大小。 | `rowset=16` 表示当前算子的向量化大小为 16。 |
| access | 该算子为了完成计算所需要访问的列列表。其顺序可能与 `output` 不同，通常与索引结构相关。 | `access([TBL2.COL1], [TBL2.COL2], [TBL2.COL3], [TBL2.COL4])` 表示需要读取 `col1`、`col2`、`col3`、`col4` 这些列的值。 |
| partitions | 查询需要扫描的分区。 | `partitions(p0)` 表示本次查询只访问了名为 `p0` 的分区。   #### 说明    如果表是非分区表，那么整个表就是一个单独的分区 `p0`。 |
| is_index_back | 表示该算子是否需要 “回表” 操作。 | `is_index_back=true` 表示需要回表。因为查询使用了索引 `idx_tbl2`（基于 `col2, col3`），但需要返回的 `col4` 列不在该索引中，因此必须回主表获取。 |
| is_global_index | 表示本次查询是否使用了全局索引。 | `is_global_index=false` 表示没有使用全局索引。 |
| filter_before_indexback | 一个布尔数组，与 `filter` 中的条件一一对应，表明该 `filter` 是可以直接在索引上进行计算，还是需要索引回表之后才能计算。 | `filter_before_indexback[true,false]` 对应 `filter` 中的两个条件：   - `true`：`TBL2.COL3 < 1` 可以在扫描索引 `idx_tbl2` 时直接判断（`col3` 是索引列），能提前过滤数据，减少回表行数。 - `false`：`TBL2.COL4 < 1` 必须在回表获取 `col4` 列值后才能判断。 |
| range_key | 表示扫描范围的行键（`rowkey` 列），决定了数据的排序方式。对于表（主表）而言，行键就是主键；对于索引，行键就是索引键。 | `range_key([TBL2.COL2], [TBL2.COL3], [TBL2.COL1])` 表示索引 `idx_tbl2` 的实际键顺序是 `(col2, col3)`，并自动附加了主键 `col1` 以保证唯一性。 |
| range | 索引扫描的起止范围，格式为 `(起始键值 ; 结束键值)`。 | `range(MIN,MIN,MIN ; 1,MIN,MIN)` 定义了具体的扫描边界：   - 起始：从 `(col2=最小值, col3=最小值, col1=最小值)` 开始。 - 结束：扫描到 `(col2=1, col3=最小值, col1=最小值)` 之前停止。这个范围由 `col2 < 1` 决定。 |
| range_cond | 决定上述扫描范围 (`range`) 的查询条件。 | `range_cond([TBL2.COL2 < 1])` 表明，只有 `col2 < 1` 这个条件被用于快速定位索引的扫描起止点。其他条件（`col3 < 1, col4 < 1`）则用于扫描后的过滤。 |

## DISTRIBUTED TABLE RANGE SCAN

`DISTRIBUTED TABLE RANGE SCAN` 是针对全局索引或分布式表进行区间扫描的操作。当表被分区，且查询使用了全局索引时，优化器会选择此算子来跨分区扫描索引数据。

### DISTRIBUTED TABLE RANGE SCAN 示例

1. 创建 Hash 分区表 `tbl3`，定义列 `col1` 为主键。

   ```shell
   obclient> CREATE TABLE tbl3(col1 INT PRIMARY KEY, col2 INT, col3 INT)
       PARTITION BY HASH(col1) PARTITIONS 4;

   ```
 2. 在表 `tbl3` 上基于列 `col2` 创建全局索引 `idx_tbl3`。

   ```shell
   obclient> CREATE INDEX idx_tbl3 ON tbl3(col2) GLOBAL;

   ```
 3. Q3：查看含 `DISTRIBUTED TABLE RANGE SCAN` 类型的执行计划。

   ```shell
   obclient> EXPLAIN SELECT * FROM tbl3
       WHERE col2 = 1;

   ```

   返回结果如下：

   ```shell
   +-----------------------------------------------------------------------------+
   | Query Plan                                                                  |
   +-----------------------------------------------------------------------------+
   | ======================================================================      |
   | |ID|OPERATOR                    |NAME          |EST.ROWS|EST.TIME(us)|      |
   | ----------------------------------------------------------------------      |
   | |0 |DISTRIBUTED TABLE RANGE SCAN|TBL3(IDX_TBL3)|1       |5           |      |
   | ======================================================================      |
   | Outputs & filters:                                                          |
   | -------------------------------------                                       |
   |   0 - output([TBL3.COL1], [TBL3.COL2], [TBL3.COL3]), filter(nil), rowset=16 |
   |       access([TBL3.COL1], [TBL3.COL2], [TBL3.COL3]), partitions(p0)         |
   |       is_index_back=true, is_global_index=true,                             |
   |       range_key([TBL3.COL2], [TBL3.COL1]), range(1,MIN ; 1,MAX),            |
   |       range_cond([TBL3.COL2 = 1])                                           |
   +-----------------------------------------------------------------------------+
   12 rows in set

   ```

在 Q3 查询结果中，算子类型（`OPERATOR`）使用的是 `DISTRIBUTED TABLE RANGE SCAN`。执行计划 `Outputs & filters` 部分各个参数的详细解释如下：

| 信息名称 | 含义 | 示例说明 |
| --- | --- | --- |
| output | 该算子最终输出的列列表。 | `output([TBL3.COL1], [TBL3.COL2], [TBL3.COL3])` 表示查询将返回表 `tbl1` 中的 `col1`、`col2`、`col3` 三列。 |
| filter | 该算子需要应用的过滤条件（谓词）。 | `filter(nil)` 表示没有额外的过滤条件。条件 `col2 = 1` 已在索引扫描时作为范围条件（`range_cond`）应用，因此在此算子内无需再次过滤。 |
| rowset | 当前算子的向量化大小。 | `rowset=16` 表示当前算子的向量化大小为 16。 |
| access | 该算子为了完成计算所需要访问的列列表。其顺序可能与 `output` 不同，通常与索引结构相关。 | `access([TBL3.COL1], [TBL3.COL2], [TBL3.COL3])` 表示需要读取 `col1`、`col2`、`col3` 这些列的值。 |
| partitions | 查询需要扫描的分区。 | `partitions(p0)` 表示本次查询只访问了名为 `p0` 的分区。表 `TBL3` 是 `HASH(col1)` 分区，共有 4 个分区。优化器通过全局索引 `idx_tbl3` 定位到满足 `col2 = 1` 的数据行全部存储在分区 `p0` 中，因此只需扫描该分区，避免了全表扫描。 |
| is_index_back | 表示该算子是否需要 “回表” 操作。 | `is_index_back=true` 表示需要回表。因为索引 `idx_tbl3` 仅包含 `col2` 和主键 `col1`。为了获取 `col3` 的值，系统在通过索引找到目标行后，必须根据主键 `col1` 回到主表的数据分区中取出 `col3`。 |
| is_global_index | 表示本次查询是否使用了全局索引。 | `is_global_index=true` 表示使用了全局索引。本次扫描使用的是全局索引（`idx_tbl3`）。全局索引是独立于表分区结构的索引，其数据可以分布在与主表不同的分区上，适用于像 Q3 这样在非分区键上进行查询的场景。 |
| range_key | 表示扫描范围的行键（`rowkey` 列），决定了数据的排序方式。对于表（主表）而言，行键就是主键；对于索引，行键就是索引键。 | `range_key([TBL3.COL2], [TBL3.COL1])` 表示扫描首先依据索引首列 `col2`，在 `col2` 值相同的情况下，再依据主键 `col1` 排序。 |
| range | 索引扫描的起止范围，格式为 `(起始键值 ; 结束键值)`。 | `range(1,MIN ; 1,MAX)` 定义了具体的扫描边界，由于查询条件是 `col2 = 1`，所以扫描所有 `col2` 为 1 的索引条目。起始点是 `(1, 最小值)`，结束点是 `(1, 最大值)`，即覆盖该条件下所有可能的 `col1` 值。 |
| range_cond | 决定上述扫描范围 (`range`) 的查询条件。 | `range_cond([TBL3.COL2 = 1])` 表示上述扫描范围（`range`）的查询条件 `col2 = 1`，这个条件使得优化器能够使用索引进行高效的范围扫描，而不是全索引扫描。 |

## TABLE SKIP SCAN

`TABLE SKIP SCAN` 是一种特殊的范围扫描，能够 “跳跃” 地利用联合索引的后缀列进行查询。当查询条件包含了联合索引的非最左列，且该列的选择性较好时，优化器可能选择此算子来避免全表扫描。

### TABLE SKIP SCAN 示例

1. 创建表 `tbl4`，定义列 `col1` 为主键。

   ```shell
   obclient> CREATE TABLE tbl4(col1 INT PRIMARY KEY, col2 INT, col3 INT);

   ```
 2. 在表 `tbl4` 上基于列 `col2` 和 `col3` 创建索引 `idx_tbl4`。

   ```shell
   obclient> CREATE INDEX idx_tbl4 ON tbl4(col2, col3);

   ```
 3. Q4：查看含 `TABLE SKIP SCAN` 类型的执行计划。

   ```shell
   obclient> EXPLAIN SELECT /*+ INDEX_SS(tbl4 idx_tbl4) */ * FROM tbl4
       WHERE col3 = 1;

   ```

   #### 说明

   `INDEX_SS` Hint 指定对表对象使用特定索引进行 index skip scan 扫描。

   返回结果如下：

   ```shell
   +-----------------------------------------------------------------------------------------------------+
   | Query Plan                                                                                          |
   +-----------------------------------------------------------------------------------------------------+
   | =========================================================                                           |
   | |ID|OPERATOR       |NAME          |EST.ROWS|EST.TIME(us)|                                           |
   | ---------------------------------------------------------                                           |
   | |0 |TABLE SKIP SCAN|TBL4(IDX_TBL4)|1       |3           |                                           |
   | =========================================================                                           |
   | Outputs & filters:                                                                                  |
   | -------------------------------------                                                               |
   |   0 - output([TBL4.COL1], [TBL4.COL2], [TBL4.COL3]), filter([TBL4.COL3 = 1]), rowset=16             |
   |       access([TBL4.COL1], [TBL4.COL3], [TBL4.COL2]), partitions(p0)                                 |
   |       is_index_back=false, is_global_index=false, filter_before_indexback[false],                   |
   |       range_key([TBL4.COL2], [TBL4.COL3], [TBL4.COL1]), range(MIN,MIN,MIN ; MAX,MAX,MAX)always true |
   |       prefix_columns_cnt = 1 , skip_scan_range(1,MIN ; 1,MAX)                                       |
   +-----------------------------------------------------------------------------------------------------+
   12 rows in set

   ```

在 Q4 查询结果中，算子类型（`OPERATOR`）使用的是 `TABLE SKIP SCAN`。执行计划 `Outputs & filters` 部分各个参数的详细解释如下：

| 信息名称 | 含义 | 示例说明 |
| --- | --- | --- |
| output | 该算子最终输出的列列表。 | `output([TBL4.COL1], [TBL4.COL2], [TBL4.COL3])` 表示查询将返回表 `tbl4` 中的 `col1`、`col2`、`col3` 三列。 |
| filter | 该算子需要应用的过滤条件（谓词）。 | `filter([TBL4.COL3 = 1])` 表示在数据扫描后，会应用 `col3 = 1` 的过滤条件。 |
| rowset | 当前算子的向量化大小。 | `rowset=16` 表示当前算子的向量化大小为 16。 |
| access | 该算子为了完成计算所需要访问的列列表。其顺序可能与 `output` 不同，通常与索引结构相关。 | `access([TBL4.COL1], [TBL4.COL3], [TBL4.COL2])` 表示需要读取 `col1`、`col2`、`col3` 这些列的值。 |
| partitions | 查询需要扫描的分区。 | `partitions(p0)` 表示本次查询只访问了名为 `p0` 的分区。   #### 说明    如果表是非分区表，那么整个表就是一个单独的分区 `p0`。 |
| is_index_back | 表示该算子是否需要 “回表” 操作。 | `is_index_back=false` 表示本次扫描不需要回表。 |
| is_global_index | 表示本次查询是否使用了全局索引。 | `is_global_index=false` 表示使用的索引是一个普通索引，而非全局索引。 |
| filter_before_indexback | 一个布尔数组，与 `filter` 中的条件一一对应，表明该 `filter` 是可以直接在索引上进行计算，还是需要索引回表之后才能计算。 | `filter_before_indexback[false]` 对应唯一的过滤条件 `col3 = 1`。`false` 表示这个条件不能在扫描索引 `idx_tbl4` 时直接应用，因为 `col3` 不是该复合索引 `(col2, col3, col1)` 的首列。这正是触发 `SKIP SCAN` 的原因。 |
| range_key | 表示扫描范围的行键（`rowkey` 列），决定了数据的排序方式。对于表（主表）而言，行键就是主键；对于索引，行键就是索引键。 | `range_key([TBL4.COL2], [TBL4.COL3], [TBL4.COL1])` 表示扫描首先依据索引首列 `col2`，然后是第二列 `col3`，在 `col2` 和 `col3` 值相同的情况下，再依据主键 `col1` 排序。 |
| range | 索引扫描的起止范围，格式为 `(起始键值 ; 结束键值)`。 | `range(MIN,MIN,MIN ; MAX,MAX,MAX)always true` 表示优化器计划扫描整个索引。`always true` 是因为查询条件 `col3=1` 不包含索引首列 `col2`，无法在索引层确定精确的起点和终点。 |
| prefix_columns_cnt | `TABLE SKIP SCAN` 类型特有参数。表示在跳跃扫描中，被跳过的前缀列的个数。 | `prefix_columns_cnt = 1` 表示跳跃扫描跳过了索引键中的第 1 列（即 `col2`），直接从第 2 列 `col3` 开始扫描。 |
| skip_scan_range | `TABLE SKIP SCAN` 类型特有参数。表示从索引后缀列中抽取的扫描范围。 | `skip_scan_range(1,MIN ; 1,MAX)` 表示跳过的首列 `col2` 的每一个唯一值，都执行一次针对 `col3=1` 的范围扫描，并将结果合并。这里 `(1, MIN ; 1, MAX)` 示意了对于某个具体的 `col2` 值，在 `col3=1` 这个点上的扫描范围。 |

Q4 查询中 `TABLE SKIP SCAN` 可以在满足一定条件下利用已有的索引来加速扫描。OceanBase 数据库在满足如下限制条件时会尝试选择 `TABLE SKIP SCAN`：

- 表上有收集过统计信息。
 - 查询条件中包含联合索引的后缀列，并且不是其他索引最左前缀。
 - 优化器比较 `TABLE SKIP SCAN` 和全表扫描的代价，发现 `TABLE SKIP SCAN` 代价更低。

## TABLE FULL SCAN

`TABLE FULL SCAN` 表示全表扫描。当执行计划中的 `range` 范围是 `(MIN ; MAX)` 时，即代表真正意义上的全表扫描。这通常发生在没有可用索引、或优化器判断全表扫描代价更低的情况下。

### TABLE FULL SCAN 示例

1. 创建表 `tbl5`。

   ```shell
   obclient> CREATE TABLE tbl5(col1 INT, col2 INT, col3 INT);

   ```
 2. Q5：查看含 `TABLE FULL SCAN` 类型的执行计划。

   ```shell
   obclient> EXPLAIN SELECT * FROM tbl5
       WHERE col1 = 1;

   ```

   返回结果如下：

   ```shell
   +-----------------------------------------------------------------------------------------+
   | Query Plan                                                                              |
   +-----------------------------------------------------------------------------------------+
   | ===============================================                                         |
   | |ID|OPERATOR       |NAME|EST.ROWS|EST.TIME(us)|                                         |
   | -----------------------------------------------                                         |
   | |0 |TABLE FULL SCAN|TBL5|1       |3           |                                         |
   | ===============================================                                         |
   | Outputs & filters:                                                                      |
   | -------------------------------------                                                   |
   |   0 - output([TBL5.COL1], [TBL5.COL2], [TBL5.COL3]), filter([TBL5.COL1 = 1]), rowset=16 |
   |       access([TBL5.COL1], [TBL5.COL2], [TBL5.COL3]), partitions(p0)                     |
   |       is_index_back=false, is_global_index=false, filter_before_indexback[false],       |
   |       range_key([TBL5.__pk_increment]), range(MIN ; MAX)always true                     |
   +-----------------------------------------------------------------------------------------+
   11 rows in set

   ```

在 Q5 查询结果中，算子类型（`OPERATOR`）使用的是 `TABLE FULL SCAN`。执行计划 `Outputs & filters` 部分各个参数的详细解释如下：

| 信息名称 | 含义 | 示例说明 |
| --- | --- | --- |
| output | 该算子最终输出的列列表。 | `output([TBL5.COL1], [TBL5.COL2], [TBL5.COL3])` 表示查询将返回表 `tbl5` 中的 `col1`、`col2`、`col3` 三列。 |
| filter | 该算子需要应用的过滤条件（谓词）。 | `filter([TBL5.COL1 = 1])` 表示扫描数据时，会应用过滤条件 `col1 = 1`。 |
| rowset | 当前算子的向量化大小。 | `rowset=16` 表示当前算子的向量化大小为 16。 |
| access | 该算子为了完成计算所需要访问的列列表。其顺序可能与 `output` 不同，通常与索引结构相关。 | `access([TBL5.COL1], [TBL5.COL2], [TBL5.COL3])` 表示需要读取 `col1`、`col2`、`col3` 这些列的值。 |
| partitions | 查询需要扫描的分区。 | `partitions(p0)` 表示本次查询只访问了名为 `p0` 的分区。   #### 说明    如果表是非分区表，那么整个表就是一个单独的分区 `p0`。 |
| is_index_back | 表示该算子是否需要 “回表” 操作。 | `is_index_back=false` 表示不需要回表。因为 Q5 查询是直接对主表进行全表扫描（`TABLE FULL SCAN`），没有使用索引。 |
| is_global_index | 表示本次查询是否使用了全局索引。 | `is_global_index=false` 表示扫描的不是全局索引。本次扫描对象是表本身（主表）。 |
| filter_before_indexback | 一个布尔数组，与 `filter` 中的条件一一对应，表明该 `filter` 是可以直接在索引上进行计算，还是需要索引回表之后才能计算。 | `filter_before_indexback[false]` 表示过滤条件 `col1 = 1` 无法在索引回表前计算。因为 Q5 查询是主表扫描，不涉及索引，故此参数为 `false`。 |
| range_key | 表示扫描范围的行键（`rowkey` 列），决定了数据的排序方式。对于表（主表）而言，行键就是主键；对于索引，行键就是索引键。 | `range_key([TBL5.__pk_increment])` 表示扫描的 `rowkey` 列是 `__pk_increment`。这是 OceanBase 数据库为无主键表自动生成的隐藏主键列。 |
| range | 索引扫描的起止范围，格式为 `(起始键值 ; 结束键值)`。 | `range(MIN ; MAX)always true` 表示扫描范围从行键的最小值到最大值，且这个条件恒成立。这是全表扫描的典型特征。 |

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
