pingcap / pingcap/tidb

server: support CLIENT_OPTIONAL_RESULTSET_METADATA

Open
#68,597 0 comments 1 reaction 0 assignees View on GitHub
contribution type/feature-request
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Feature Request

**Is your feature request related to a problem? Please describe:**

TiDB currently does not support MySQL's `CLIENT_OPTIONAL_RESULTSET_METADATA` capability and the `@@session.resultset_metadata` protocol behavior. MySQL clients that already know the shape of repeated result sets still have to receive and parse column-definition metadata for every result set.

This is especially visible for high-QPS point-select or point-select-like workloads where each query returns only a few rows. In those cases, the metadata packets can be a large part of the response compared with the actual row data, adding server-side metadata generation cost, client-side parsing cost, and extra network bytes.

External references:

- MySQL C API documentation says suppressing metadata transfer can improve performance, particularly for sessions that execute many queries returning few rows each: https://dev.mysql.com/doc/c-api/8.4/en/c-api-optional-metadata.html
- MySQL WL#8134 explains the motivation: constructing/parsing and sending/receiving result-set metadata consumes server, client, and network resources, and metadata can be much larger than row data. It also includes a mysqlslap point-select style benchmark where ignoring metadata increased TPS and reduced network send bytes: https://dev.mysql.com/worklog/task/?id=8134

Additional historical context:

- The standard MySQL command-line client does not negotiate `CLIENT_OPTIONAL_RESULTSET_METADATA` by default, so users will not see this behavior just by setting a session variable from the normal client.
- C API users can opt in by passing `CLIENT_OPTIONAL_RESULTSET_METADATA` in the `client_flag` argument to `mysql_real_connect()`, then set the session-level `resultset_metadata` variable to suppress metadata.
- Around 2012, Twitter MySQL had a similar patch. A later MySQL 5.6.16 port of that idea tested several metadata modes on a 40-column point-select workload:

```sql
CREATE TABLE test_meta_impact (
abcdefg1 int(11) NOT NULL AUTO_INCREMENT,
abcdefg2 int(11) DEFAULT NULL,
...
abcdefg40 int(11) DEFAULT NULL,
PRIMARY KEY (abcdefg1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

```bash
mysqlslap --no-defaults -uxx --create-schema=test -h$host -P $port \
--number-of-queries=1000000000 --concurrency=100 \
--query='SELECT * FROM test.test_meta_impact where abcdefg1 = 2'
```

| Mode | Behavior | Result |
| --- | --- | --- |
| `METADATA_FULL` | Return all metadata, default | 34.8k TPS, Net send 113M |
| `METADATA_REAL_COLUMN` | Only real column names | 72k TPS, Net send 111M |
| `METADATA_FAKE_COLUMN` | Fake column names `1..N` | 92k TPS, Net send 116M |
| `METADATA_NULL_COLUMN` | Use `NULL` metadata | 96k TPS, Net send 115M |
| `METADATA_IGNORE` | Ignore metadata | 138k TPS, Net send 30M |

Those numbers are from a patched MySQL experiment rather than TiDB, so they should be treated as directional. They still show why removing result-set metadata can matter for point-select workloads: the response payload dropped by more than 3x and throughput increased substantially when metadata was skipped.

**Describe the feature you'd like:**

Support MySQL-compatible optional result set metadata in TiDB:

- Advertise `CLIENT_OPTIONAL_RESULTSET_METADATA` during handshake when TiDB supports this behavior.
- Add MySQL-compatible `@@session.resultset_metadata` values:
- `FULL` as the default, preserving current behavior.
- `NONE` to suppress result-set metadata after the client has negotiated `CLIENT_OPTIONAL_RESULTSET_METADATA`.
- Return an error when a client that did not negotiate `CLIENT_OPTIONAL_RESULTSET_METADATA` tries to set `@@session.resultset_metadata = NONE`, matching MySQL compatibility expectations.
- Apply the protocol behavior consistently to text protocol result sets and prepared statement result sets.

The important compatibility property is that clients that do not set `CLIENT_OPTIONAL_RESULTSET_METADATA` should see no protocol change.

**Describe alternatives you've considered:**

Keeping the current behavior is compatible, but it leaves repeated metadata transfer on the hot path for clients and proxies that can safely cache or already know result-set metadata.

Client-side caching alone cannot remove the wire traffic or server-side metadata construction cost unless the server participates through the MySQL protocol capability.

**Teachability, Documentation, Adoption, Migration Strategy:**

This should be opt-in and backward compatible:

- Default behavior remains `FULL`.
- Only clients that negotiate `CLIENT_OPTIONAL_RESULTSET_METADATA` can use `@@session.resultset_metadata = NONE`.
- Existing clients continue to receive full result-set metadata.
- Documentation should describe the capability, the session variable, and the restriction for non-negotiating clients.

Suggested labels: `type/feature-request`, `component/server`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.