# 从读副本查询

> 在 GreptimeDB 企业版中从读副本查询的用法、读优先策略与示例。

# 从读副本查询

GreptimeDB 允许从**读副本 (Follower Region)** 读取数据，从而降低写副本 (Leader Region) 的负载并提升查询伸缩性。你可以通过 **SQL** 与 **HTTP** 两种方式设置读优先策略。

:::warning 警告
读副本（Follower Region）依赖[对象存储](/user-guide/deployments-administration/configuration.md#storage-options)（例如 AWS S3）。
由于 Follower Region 可能被调度到不同的 Datanode，它们必须通过对象存储共享 Region 数据；不支持仅使用本地存储的集群。

在允许查询从 Follower Region 读取之前，请确保在 Metasrv 和所有 Datanode 上启用 [GC](/user-guide/deployments-administration/manage-data/gc.md)。只有在启用 GC 时，才支持从 Follower Region 读取。
:::

## 读优先策略

`READ_PREFERENCE` 支持如下取值：

- `leader`：始终从写副本读取。
- `follower`：仅从读副本读取；若不存在读副本，则查询失败。
- `follower_preferred`：优先从读副本读取；若存在读副本，则随机选择一个读副本读取；若不存在读副本，则回退到写副本。
- `random`：随机选择一个写副本或读副本读取。

## SQL 协议

在 SQL 会话中设置读优先：

```sql
SET READ_PREFERENCE = 'follower';
```

---

## HTTP 协议

在 HTTP 请求中通过请求头指定 `X-Greptime-Read-Preference`：

```bash
curl -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "X-Greptime-Read-Preference: follower" \
  -d "sql=select * from monitoring" \
  http://localhost:4000/v1/sql
```

---

## 示例：从读副本读取

在从读副本读取之前，需要先为表添加读副本。参见[副本管理](/enterprise/read-replicas/manage-read-replicas.md)。

向示例表插入数据：

```sql
INSERT INTO foo (ts, i, s)
VALUES
  (1, -1, 's1'),
  (2, 0, 's2'),
  (3, 1, 's3');
```

设置从读副本读取：

```sql
SET READ_PREFERENCE = 'follower';
```

查询数据：

```sql
SELECT * FROM foo ORDER BY ts;

+----------------------------+------+------+
| ts                         | i    | s    |
+----------------------------+------+------+
| 1970-01-01 00:00:00.001000 |   -1 | s1   |
| 1970-01-01 00:00:00.002000 |    0 | s2   |
| 1970-01-01 00:00:00.003000 |    1 | s3   |
+----------------------------+------+------+
```

---

## 验证是否从读副本读取

可以使用 `EXPLAIN ANALYZE` 进行验证：

```sql
EXPLAIN ANALYZE SELECT * FROM foo ORDER BY ts;
```

- 当输出中的 `other_ranges` 大于 0 时，表示查询涉及了读副本。
- 若使用 `VERBOSE` 选项，将看到类似如下的详细信息：

```plaintext
extension_ranges: [LeaderMemtableRange{leader: Peer { id: 1, addr: "192.168.50.189:14101" }, num_rows: 2, time_range: (1::Millisecond, 2::Millisecond) ...
```

如果仅从写副本读取，上述 `extension_ranges` 段不会出现。
