第1章 认识 TiDB 与整体架构
🎯 本章学习目标
- 说清 TiDB 的定位:它不是「另一个 MySQL」,而是替代「MySQL + 分库分表中间件 + 一堆周边运维工具」的一整套分布式 SQL 方案,对上层仍暴露 MySQL 协议。
- 建立计算存储分离的架构心智,讲清四大组件职责:
TiDB Server(无状态 SQL 层)、PD(元信息 + 调度 + 全局时钟 TSO)、TiKV(分布式行存,Region 多副本)、TiFlash(列存,HTAP 分析加速)。 - 理解 TiDB 如何天生免掉分库分表:数据按 Key Range 自动切成 Region(默认约 96MB 触发分裂)、自动打散到多 TiKV 节点、多副本 Raft 强一致、扩缩容对应用透明。
- 记住几个「连接层」关键事实:默认端口 4000(不是 3306)、MySQL 协议兼容、可直接用 MySQL 的 Java 驱动与 Navicat/DBeaver 等工具。
- 用
tiup playground一条命令在本地拉起一个体验集群,并用mysql客户端与 Java(MySQL Connector/J) 各连一次,打印版本。
1.1 从「分库分表的痛」说起:TiDB 解决什么问题
你在 云岚到家第九章 里做过这样的事:订单表数据量上来后,用 ShardingSphere-JDBC 把它按用户 ID 取模拆成「4 库 × 若干表」,并且——
- 写业务代码时时刻记着分片键,查询不带
user_id就要广播到所有分片再内存归并; - 主键不能再用单库自增,得上雪花算法/号段造全局 ID;
- 跨库的 JOIN、
GROUP BY、分页、事务要么受限要么要额外处理; - 数据涨到要加机器时,面临 rebalance:新节点搬数据、灰度双写、一致性校验,一轮下来脱层皮;
- 一次
ALTER TABLE ADD COLUMN要在几十张物理表上逐个执行。
这些复杂度,本质都来自「把一张逻辑表人为拆成 N 张物理表,再靠中间件在应用侧兜住拆分逻辑」。
TiDB 换了一个思路:让「一张表」在底层就自然是分布式的。你不拆表,数据自己按范围切成 Region、自己分散到多台存储节点、自己用 Raft 保持多副本一致、自己在线扩缩容。应用看到的还是一个 MySQL 样的库、一张表、一条普通 SQL——分库分表中间件替你操心的那些事,下沉到了数据库内核里自动化完成。
| 你在分库分表里做的 | 在 TiDB 里变成 |
|---|---|
| 选分片键、写路由规则 | 无需分片键,数据自动按 RowID/主键切 Region |
| 全局 ID 方案(雪花/号段) | 普通自增 / AUTO_RANDOM,TiDB 内部分配 |
| 应用/中间件处理跨库 JOIN、聚合 | 一条标准 SQL,引擎层分布式执行 |
| 加机器要做 rebalance、双写迁移 | 加 TiKV 节点,PD 自动搬 Region,对应用透明 |
| DDL 铺到 N 张物理表 | 一条 ALTER TABLE,在线异步执行一次搞定 |
一句话:分库分表是「把分布式复杂度甩给开发和运维」,TiDB 是「把分布式复杂度关进数据库内核」。 本课程的主线就是带你完成这次「责任转移」的认知切换。
1.2 整体架构:计算与存储分离的四大组件

逐个组件用 MySQL/分库分表的语言解释:
1.2.1 TiDB Server(计算层)
- 干的事:接收 MySQL 协议的连接和 SQL,做解析 → 优化 → 生成分布式执行计划,再向 TiKV/TiFlash 取数据、汇总返回。
- 无状态:它不存数据,所以可以随意起多个实例,前面挂个 LB 做接入均衡;某个 TiDB 挂了,客户端重连到别的即可。
- 对应分库分表世界:它就像「ShardingSphere 中间件 + MySQL Server」合体,只不过这个「中间件」是数据库官方内核,能力远强于外挂中间件(能下推、能跨分片事务、能并行执行)。
1.2.2 PD(Placement Driver,大脑)
- 三件事:① 存元信息(哪个 Region 的副本在哪些 TiKV 上);② 调度(热点 Region 迁移、副本均衡、故障补副本);③ 分配 TSO(全局单调递增的时间戳,用于分布式事务的快照读与冲突检测)。
- 本身高可用(Raft,建议奇数节点)。
- 对应分库分表世界:它承担了「注册中心 + 配置中心 + 全局发号器 + 再平衡调度器」的角色,而且是自动的——你分库分表里手写/运维的那套,PD 内核全包了。
1.2.3 TiKV(行存层,事务数据的家)
- 分布式 Key-Value 存储,底层每个节点用 RocksDB。数据的基本单位是 Region:一段连续的 Key Range(默认约 96MB 触发分裂、144MB 强制分裂),一个 Region 的多副本(默认 3 副本)分散在不同 TiKV 节点上,用 Multi-Raft 协议保证强一致——多数派写成功事务才提交。
- 这就是 TiDB「天生分布式」的根基:你的「一张大表」在 TiKV 里早就被切成无数个 Region 散在集群里了,根本不需要你分库分表。
- 对应分库分表世界:Region ≈ 你拆出来的「分片/物理表」,但它是自动切、自动搬、自动多副本的,对你完全透明。
1.2.4 TiFlash(列存层,分析加速器,可选)
- 一类特殊存储节点:把 TiKV 的数据以列式再存一份副本(通过 Raft Learner 异步但实时同步),专门加速 OLAP 大宽表扫描/聚合。
- 有了它,同一份数据既能走 TiKV 做事务(OLTP),又能走 TiFlash 做分析(OLAP)——这就是 HTAP,省掉「业务库 + 抽数到数仓」的链路。
- 对应分库分表世界:以前你在分库分表上跑复杂报表要拖垮所有分片,要么另建数仓;TiDB 用 TiFlash 原生解决(第 6 章详解)。
1.3 关键事实:连接层的「MySQL 味」
对 Java 程序员而言,最重要的一条是:连 TiDB 基本等于连 MySQL。
| 维度 | MySQL | TiDB |
|---|---|---|
| 默认端口 | 3306 | 4000 |
| 通信协议 | MySQL 协议 | 兼容 MySQL 协议 |
| Java 驱动 | com.mysql.cj.jdbc.Driver | 同一个,照用(也可用 MariaDB 驱动) |
| GUI 工具 | Navicat/Workbench/DBeaver | 都适用(填端口 4000 即可) |
| 命令行 | mysql -uroot -p | mysql -h -P 4000 -uroot -p(用同款客户端) |
| SQL 方言 | MySQL 5.7/8.0 | 兼容常用语法(差异见第 2 章) |
| 生态工具 | mysqldump/MyBatis... | 多数可用(迁移与备份有 TiDB 专用工具,第 7 章) |
注意端口这个最常见的坑:很多人按 3306 连 TiDB 连不上——TiDB Server 的 SQL 端口是 4000,另外 PD 默认 2379、TiKV 默认 20160。做实验记牢 4000。
1.4 起一个本地体验集群:tiup playground
官方集群管理工具 tiup 把装 TiDB 变成一条命令。先装 tiup,再起一个最小拓扑的体验集群:
# 安装 tiup(Linux/macOS)
curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
source ~/.bash_profile # 使 tiup 进入 PATH
# 一条命令拉起单机体验集群(TiDB+PD+TiKV+TiFlash 各跑在本机)
tiup playground v8.5.0 --tiflash 1两个常用变体:想知道能填哪些版本号,先跑
tiup list tidb;playground 默认退出即清空数据,想下次接着用同一个集群,加--tag:tiup --tag tidbdemo playground v8.5.0 --tiflash 1(本章课后练习里有「重启 TiDB 观察自增跳号」一题,必须靠--tag才能保住数据)。
启动成功后,输出里会直接告诉你怎么连(每行都是 tiup 的真实回显,记住端口 4000):
Starting component `playground`: ...
TiDB PID 2149, Port 4000, Binary /home/tidb/.tiup/components/tidb/v8.5.0/tidb-server
TiKV PID 2173, Port 20160, Binary /home/tidb/.tiup/components/tikv/v8.5.0/tikv-server
PD PID 2158, Port 2379, Binary /home/tidb/.tiup/components/pd/v8.5.0/pd-server
CLUSTER START SUCCESSFULLY, Enjoy it ^-^
To connect TiDB: mysql --comment --host 127.0.0.1 --port 4000 -u root -p (no password)
To view the dashboard: http://127.0.0.1:2379/dashboard
PD client endpoints: [127.0.0.1:2379]
To view the Prometheus: http://127.0.0.1:9090
To view the Grafana: http://127.0.0.1:3000用 mysql 客户端连上后跑三条确认:
SELECT version(); -- 形如 8.0.11-TiDB-v8.5.0:前缀是它冒充的 MySQL 版本,后才是 TiDB 真版本
SELECT tidb_version()\G -- 完整构建信息(Release Version / Git Branch / 编译时间)
SHOW COMPONENTS; -- 看集群里 PD/TiDB/TiKV/TiFlash 各自的地址与版本
SHOW STORES; -- 看存储节点(TiKV)的容量、Region 数、Leader 分布playground 只用于学习
tiup playground 是为「本地体验/写代码」设计的,所有进程在一台机器上、副本不齐全、没有容灾。生产环境必须用 tiup cluster 按真实拓扑部署(第 7 章),切勿把 playground 直接上生产。
1.4.1 Windows / 无 Linux 环境
TiDB Server 只出 Linux 二进制,tiup 也不支持 Windows,所以 Windows 上做实验有四条路,按「能做到的事」从多到少排:
| 方案 | 怎么起 | 能做到 | 做不到 |
|---|---|---|---|
| ① WSL2 里装 tiup(推荐) | wsl --install 后进 Ubuntu,照 1.4 的 Linux 命令装 tiup | 全套:playground、Dashboard、Grafana、Lightning/BR、多 TiDB 实例 | 磁盘 IO 比原生 Linux 慢一些 |
| ② Docker 跑单容器 | docker run -d -p 4000:4000 pingcap/tidb:latest | 只跑 SQL 层(存储用进程内的 mock-tikv,数据不落盘) | 没有 Region/热点/TiFlash/BR,第 4、6、7 章的实验全做不了 |
| ③ TiDB Cloud Serverless(免费) | 邮箱注册 tidbcloud.com/free-trial 建 Serverless 集群,Connect 面板拿 host/端口/用户名/密码 | 所有纯 SQL 实验 + Java 连接;MySQL 协议,端口通常是 443 | 碰不到集群内部(Dashboard、Region、BR、tiup) |
| ④ TiDB Labs 在线实验室 | 浏览器打开 labs.pingcap.com 选一个教程沙箱 | 免安装体验 Dashboard、Lightning、TiCDC 等 | 环境是别人编排好的,不能自定义拓扑 |
选路原则:只要你想做完第 4/6/7 章(Region、热点、TiFlash、备份、扩缩容),必须走 ①;只想验证「MySQL 驱动能不能连、SQL 行为对不对」,走 ③ 最省事。本课程后面每章答案里都会标出该题需要 ①②③ 中的哪一种。
1.5 跑通第一个 Java 连接
关键:依赖、驱动类、连接串都用 MySQL 那一套,只是端口换成 4000。
<!-- pom.xml:就是普通 MySQL 驱动,TiDB 不需要专用驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>import java.sql.*;
public class TidbFirstConnect {
public static void main(String[] args) throws Exception {
// 和连 MySQL 唯一明显的区别:端口是 4000
String url = "jdbc:mysql://127.0.0.1:4000/test"
+ "?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
String user = "root";
String pwd = ""; // playground 默认 root 无密码
try (Connection conn = DriverManager.getConnection(url, user, pwd);
Statement st = conn.createStatement()) {
// 建一张表(AUTO_RANDOM 主键,第 4 章细讲),再查版本确认连的是 TiDB 而不是 MySQL
st.execute("CREATE TABLE IF NOT EXISTS demo(id bigint primary key auto_random, note varchar(50))");
try (ResultSet rs = st.executeQuery("SELECT version(), current_database()")) {
if (rs.next()) {
System.out.println("连上了 TiDB!版本:" + rs.getString(1));
System.out.println("当前库:" + rs.getString(2));
}
}
}
}
}你会的 MySQL JDBC 编程模型(
DriverManager/PreparedStatement/ResultSet)、连接池(HikariCP/Druid)、ORM(MyBatis/JPA)在 TiDB 上直接可用。第 5 章专门讲连接池参数与事务模式在 TiDB 上需要额外注意的点。
1.6 本章小结
- TiDB 的定位:替代「MySQL + 分库分表中间件 + 运维工具链」的一体化分布式 SQL 数据库,上层仍说 MySQL 协议。
- 架构是计算存储分离:
TiDB Server(无状态 SQL 层) +PD(元信息/调度/TSO 大脑) +TiKV(行存,Region 多副本 Raft) +TiFlash(列存,HTAP 分析,可选)。 - 免掉分库分表的根基:数据按 Region 自动切分、自动打散、自动多副本、在线扩缩容对应用透明——分片键、全局 ID、rebalance 这些你不用管了。
- 连接层照搬 MySQL,但默认端口 4000;Java 用 MySQL 驱动即可。
- 起集群:
tiup playground(学习用),生产用tiup cluster。
✏️ 课后练习
- 用
tiup playground起集群,mysql -P 4000连上后执行SHOW COMPONENTS;和SHOW STORES;,把各组件地址/端口抄下来,确认 SQL 端口是 4000。 - 把 1.5 的 Java Demo 跑通,并在连接串里故意把端口写成 3306,观察报错,体会「端口是最常见的第一坑」。
- 用
CREATE TABLE t(a int);建表后用SHOW CREATE TABLE t;观察它的SHARD_ROW_ID_BITS、PRE_SPLIT_REGIONS等 TiDB 特有属性,并查出它的表 ID 与隐藏行 ID 列(为第 4 章埋钩子)。 - 打开浏览器访问
http://127.0.0.1:2379/dashboard,在 TiDB Dashboard 里找到「SQL 语句分析」,回看刚才你执行的 SQL——熟悉这个后续第 6/7 章反复用的可视化控制台。
📖 参考答案
本章 4 题都是「环境 + 观察」类。四题都能在 1.4.1 的方案①(WSL2 + tiup playground) 上完整做完;方案②③只能做第 2、3 题(没有 Dashboard、没有真 TiKV)。下面所有回显都是 v8.5.x playground 的实测形态,PID、时间、Region 数这类数字一定以你本机为准,但「哪一行有值、端口是多少、报错原文是什么」这些结构不会变,那才是本题要对账的东西。
第 1 题:起集群,用 SHOW COMPONENTS / SHOW STORES 抄下各组件地址端口,确认 SQL 端口是 4000
第 1 步,装 tiup(Ubuntu/WSL2 内执行,脚本会把 tiup 写进 ~/.tiup/bin 并改 PATH):
curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
source ~/.bash_profile # 或 source ~/.profile,让当前 shell 认识 tiup
tiup --version # 有版本号即安装成功
tiup list tidb | tail -5 # 看能起哪些 TiDB 版本,挑一个 LTS(本课程用 v8.5.0)第 2 步,起集群(加 --tag,否则下次重启数据就没了,第 2 章跳号实验要用它):
tiup --tag tidbdemo playground v8.5.0 --tiflash 1回显逐行解读(这就是本题要抄的东西):
TiDB PID 2149, Port 4000, Binary /home/tidb/.tiup/components/tidb/v8.5.0/tidb-server
TiKV PID 2173, Port 20160, Binary /home/tidb/.tiup/components/tikv/v8.5.0/tikv-server
PD PID 2158, Port 2379, Binary /home/tidb/.tiup/components/pd/v8.5.0/pd-server
CLUSTER START SUCCESSFULLY, Enjoy it ^-^
To connect TiDB: mysql --comment --host 127.0.0.1 --port 4000 -u root -p (no password)
To view the dashboard: http://127.0.0.1:2379/dashboard第 3 步,连上去。tiup 不带 mysql 客户端,所以三条路选一条:
sudo apt install -y mysql-client-core-8.0 # WSL2/Ubuntu 里最省事的一个包装完就有 mysql 命令
mysql --comment --host 127.0.0.1 --port 4000 -u root # root 无密码,直接回车进去
# 或者:Windows 上的 Navicat / DBeaver / MySQL Workbench 新建连接,主机填 WSL 的 IP、端口填 4000
# WSL 的 IP 用 `hostname -I` 查;只填 127.0.0.1 在老版本 WSL2 上连不通(要做端口转发)
# 或者:连 TiDB Cloud Serverless,端口通常是 443 而不是 4000,且必须加 --ssl 与 --enable-cleartext-plugin第 4 步,SHOW COMPONENTS; —— 一条命令看全集群角色。playground 单机的预期是 4 行(tidb / pd / tikv / tiflash),版本一致、地址都是 127.0.0.1:
+---------+-----------+-------+-----------------+-----------------+---------------------+-------------+
| NAME | IP | PORT | HTTP_ADDR | GRPC_ADDR | START_TIME | VERSION |
+---------+-----------+-------+-----------------+-----------------+---------------------+-------------+
| tidb | 127.0.0.1 | 4000 | 127.0.0.1:10080 | | 2026-10-02 14:03:11 | v8.5.0 |
| pd | 127.0.0.1 | 2379 | 127.0.0.1:2379 | | 2026-10-02 14:03:08 | v8.5.0 |
| tikv | 127.0.0.1 | 20160 | 127.0.0.1:20180 | 127.0.0.1:20160 | 2026-10-02 14:03:10 | 8.5.0 |
| tiflash | 127.0.0.1 | 3930 | 127.0.0.1:8234 | 127.0.0.1:3930 | 2026-10-02 14:03:14 | v8.5.0 |
+---------+-----------+-------+-----------------+-----------------+---------------------+-------------+
4 rows in set (0.01 sec)读表三个要点:① PORT 列里 4000 就是本题要找的 SQL 端口;② tidb 的 HTTP_ADDR:10080 是它的状态/指标端口(curl 127.0.0.1:10080/status 可看);③ TiKV 的 VERSION 显示成 8.5.0(没有 v 前缀)是正常的,两个组件的版本字符串格式本就不同。不同小版本这里还会多出 DEPLOY_PATH、PARENT_ADDR 等列,以你实测为准。
第 5 步,SHOW STORES; —— 看存储节点。playground 只有 1 个 TiKV,所以只有一行:
-- 先看精简版(列少、好抄):容量 / 剩余 / 磁盘使用率 / 版本
SELECT store_id, address, capacity, available, disk_usage, version
FROM information_schema.tikv_store_status;
-- store_id | address | capacity | available | disk_usage | version
-- -------- + ----------------- + -------- + --------- + ---------- + -------
-- 1 | 127.0.0.1:20160 | 500GiB | 480GiB | 0.04 | 8.5.0
-- 再看 Region 分布与角色(本题真正要抄的是 TOTAL_REGION_COUNT)
SHOW STORES STATS;第 6 步,把端口表背下来(后面每章都要用):
| 端口 | 归属 | 干什么 | 谁会去连它 |
|---|---|---|---|
| 4000 | TiDB Server | MySQL 协议 SQL 入口 | 你、驱动、Navicat |
| 10080 | TiDB Server | HTTP 状态页 / /status、指标 | 监控抓取、排障 |
| 2379 | PD | 客户端 API + Dashboard 入口 /dashboard | 应用取 TSO 不直连,但工具/浏览器要连 |
| 2380 | PD | 集群内 peer 通信 | 仅 PD 之间 |
| 20160 | TiKV | gRPC,TiDB 读写数据走这里 | TiDB / BR / pd-ctl |
| 20180 | TiKV | 状态与指标 HTTP | 监控 |
| 3930 / 8123 / 8234 | TiFlash | 内部数据同步 / HTTP / 管理端口 | 由集群内部使用 |
| 9090 / 3000 | Prometheus / Grafana | 监控与大盘(playground 会一起拉起) | 第 6、7 章 |
记法:应用只碰 4000;排障看 2379/dashboard;指标看 9090/3000;剩下的都是组件互连。
第 7 步,收尾(下次用 tiup --tag tidbdemo playground ... 数据还在;彻底清理):
# Ctrl+C 停掉 playground(前台进程),再执行:
tiup clean --all常见坑:
| 现象 | 根因 | 处理 |
|---|---|---|
按 3306 连,Connection refused | TiDB 的 SQL 端口是 4000 | 改端口,这是新手第一坑(第 2 题专门复现它) |
SHOW COMPONENTS 里没有 tiflash 行 | 起集群时没带 --tiflash 1,或用了 mock-tikv 的单容器镜像 | 重新 tiup playground v8.5.0 --tiflash 1 |
SHOW STORES 一行都没有 | 你用的是 1.4.1 方案②的 Docker 单容器(pingcap/tidb 镜像内嵌 mock-tikv,没有真 TiKV) | 只能做 SQL 实验;要看 Region/存储必须走方案① |
| playground 每次起来都是空库 | 没加 --tag | tiup --tag tidbdemo playground ... |
第 2 题:跑通 1.5 的 Java Demo,并把端口写成 3306 观察报错
第 1 步,备一个驱动 jar(不建 Maven 工程也能跑,最小路径):
mvn dependency:get -Dartifact=com.mysql:mysql-connector-j:8.3.0
# WSL/Linux 下复制到当前目录
cp ~/.m2/repository/com/mysql/mysql-connector-j/8.3.0/mysql-connector-j-8.3.0.jar ./
# Windows PowerShell 下用:
# Copy-Item $env:USERPROFILE\.m2\repository\com\mysql\mysql-connector-j\8.3.0\mysql-connector-j-8.3.0.jar .\第 2 步,把 1.5 的 TidbFirstConnect.java 原文保存好,编译并运行(JDK 17+ 可直接单文件运行):
java -cp .:mysql-connector-j-8.3.0.jar TidbFirstConnect.java # Linux/WSL 用 : 分隔
java -cp .;mysql-connector-j-8.3.0.jar TidbFirstConnect.java # Windows 用 ; 分隔第 3 步,正确的预期输出(两行,注意版本号里一定带 -TiDB-):
连上了 TiDB!版本:8.0.11-TiDB-v8.5.0
当前库:test两个观察点:① version() 返回的是 8.0.11-TiDB-vX.Y.Z 这种拼接串——8.0.11 是 TiDB 对外声称的 MySQL 兼容版本,v8.5.0 才是真身;② playground 自带一个 test 库且 root 无需密码,所以 current_database() 就是 test。
第 4 步,故意把 URL 端口改成 3306,再跑一次。分两种情况,两种都是本题要记的报错原文:
String url = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";情况 A(本机没跑 MySQL,最常见)——TCP 层就被拒,报错里没有任何 SQL 语义:
Exception in thread "main" com.mysql.cj.jdbc.exceptions.CommunicationsException:
Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago.
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
Caused by: java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.connect0(Native Method)情况 B(本机真有一个 MySQL 在 3306 上)——连上了,但连错了数据库,这才是更阴的坑:
连上了 TiDB!版本:8.0.35 ← 注意:没有 -TiDB- 字样,说明连的是真 MySQL
Exception in thread "main" java.sql.SQLSyntaxErrorException: Unknown database 'test'
-- 或者库碰巧存在时:建表成功,但后面的实验全部对不上账第 5 步,把这条自检固化成一行断言(以后所有 TiDB 工程启动时都值得打一次):
try (ResultSet rs = st.executeQuery("SELECT version()")) {
rs.next();
String v = rs.getString(1);
if (!v.contains("-TiDB-")) throw new IllegalStateException("连的不是 TiDB:" + v);
}| 报错长相 | 真实含义 | 下一步查什么 |
|---|---|---|
Connection refused | 端口没人监听 / 集群没起 | 先看 playground 那个终端还在不在跑,再到 WSL 里 `ss -lntp |
Communications link failure 但无 refused | 中间被防火墙/LB 掐了 | 云主机安全组、WSL2 的 Windows 防火墙入站规则 |
Unknown database 'test' | 端口对了、库不对(多半连到真 MySQL 了) | 看 version() 有没有 -TiDB- |
Access denied for user 'root'@'...' | 连上了但账号/密码/来源不匹配 | TiDB Cloud 的用户名是 xxxx.root 这种形式,不是 root |
第 3 题:建无主键表 t(a int),用 SHOW CREATE TABLE 观察 TiDB 特有属性,并查表 ID 与隐藏行 ID
第 1 步,建表并插三行:
CREATE TABLE t(a int);
INSERT INTO t VALUES (10),(20),(30);第 2 步,看建表语句(不是 SHOW TABLE t,TiDB 里没有这个命令,见本題末尾的坑表):
SHOW CREATE TABLE t\G*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`a` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin三个信息量都很高的细节:① 没有出现 SHARD_ROW_ID_BITS=、PRE_SPLIT_REGIONS=、AUTO_RANDOM_BASE=——说明它们都是「不写就不显示」的表级选项,默认关闭(AUTO_RANDOM_BASE 更是只有 AUTO_RANDOM 表才有);② COLLATE=utf8mb4_bin 印证了第 2 章说的「TiDB 默认排序规则区分大小写」;③ ENGINE=InnoDB 是兼容用的假字段,TiDB 里引擎永远是 TiKV,别按 MySQL 直觉去换引擎。
第 3 步,查它的表 ID 与 RowID 打散信息(第 4、6 章多次要用):
SELECT table_name, tidb_table_id, tidb_row_id_sharding_info
FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 't';
-- table_name | tidb_table_id | tidb_row_id_sharding_info
-- -----------+---------------+--------------------------
-- t | 85 | ← 空:既没主键聚簇,也没设 SHARD_ROW_ID_BITS/AUTO_RANDOM对照:建一张 AUTO_RANDOM 表再查同一列,就能看到值(第 4 章细讲):
CREATE TABLE t_ar(id BIGINT PRIMARY KEY AUTO_RANDOM(5), b INT);
SHOW WARNINGS; -- 建 AUTO_RANDOM 表后紧跟着看这句,很有用
-- Level | Code | Message
-- ------+------+--------------------------------------------
-- Note | 1105 | Available implicit allocation times: 288230376151711743
SELECT table_name, tidb_table_id, tidb_row_id_sharding_info
FROM information_schema.tables WHERE table_name IN ('t','t_ar');
-- t | 85 | ← 无主键:行靠隐藏的 _tidb_rowid 定位
-- t_ar | 86 | PK_AUTO_RANDOM_BITS=5 ← 有主键且聚簇:handle 就是主键,分片位 5第 4 步,把隐藏行 ID 「抓」出来——这是无主键表最直观的一张图:
SELECT _tidb_rowid, a FROM t ORDER BY _tidb_rowid;
-- +--------------+----+
-- | _tidb_rowid | a |
-- +--------------+----+
-- | 1 | 10 |
-- | 2 | 20 |
-- | 3 | 30 |
-- +--------------+----+
SELECT _tidb_rowid, id FROM t_ar LIMIT 3; -- ❌ ERROR 1105: column _tidb_rowid not found最后一行报错很关键:有聚簇主键的表根本没有 _tidb_rowid(handle 已经是主键了),而无主键表的 _tidb_rowid 集中递增——这就是第 4 章写热点的两个根因之一。
第 5 步,顺手看 Region(有真 TiKV 才能看到,方案②会报错):
SHOW TABLE t REGIONS;
-- REGION_ID | START_KEY | END_KEY | LEADER_ID | LEADER_STORE_ID | PEERS | SCATTERING | WRITTEN_BYTES | READ_BYTES | APPROXIMATE_SIZE(MB) | APPROXIMATE_KEYS
-- --------- + --------- + ------- + --------- + --------------- + ----- + ---------- + ------------- + -------- + -------------------- + ---------------
-- 5xxx | t_85_ | | 5xxx | 1 | ... | 0 | ... | ... | 1 | 3
-- 一行就是「这张表现在只有一个 Region」(数据量没到 96MB),第 4 章 PRE_SPLIT_REGIONS 就是把这里变多行| 错误写法 | 为什么错 | 正确写法 |
|---|---|---|
SHOW TABLE t; | TiDB/MySQL 都没有这个命令,直接语法报错 | SHOW CREATE TABLE t\G |
SHOW TABLES t; | SHOW TABLES 不能接表名 | SHOW TABLES LIKE 't%'; |
SHOW TABLE t REGIONS; 当成看结构 | 它看的是 Region 分布,不是表结构 | 两个都要会,职责不同 |
DESC t; 里找 SHARD_ROW_ID_BITS | 它是表级选项,不在列信息里 | SHOW CREATE TABLE 或 information_schema.tables.tidb_row_id_sharding_info |
第 4 题:打开 Dashboard,在「SQL 语句分析」里回看你执行过的 SQL
第 1 步,确认入口。playground 的 Dashboard 内嵌在 PD 里,无需密码:
http://127.0.0.1:2379/dashboard
# 浏览器在 Windows、集群在 WSL2 时:先试 WSL 的 IP(hostname -I 查),不行就在 WSL 里做转发:
# socat TCP-LISTEN:2379,fork,reuseaddr TCP:127.0.0.1:2379 # 或用 Windows 端 Portproxy
# TiDB Cloud Serverless(方案③)没有这个地址,对应功能在控制台的 Developer → Insights第 2 步,左侧菜单至少应有这几项(本题要用的标记出来了):
| 菜单 | 英文名 | 本课程什么时候用 |
|---|---|---|
| 语句分析 / SQL 语句分析 | Statements Analytics | 本题;第 6 章找 Top SQL |
| 慢查询 | Slow Query | 第 6 章 |
| 键值分析 / 热力图 | Key Visualizer / Heatmap | 第 4 章验热点全靠它 |
| 任务管理 / DDL | Jobs / DDL | 第 2 章看在线 DDL 进度 |
| 拓扑 / 配置 | Topology / Configuration | 第 7 章看节点与改参数 |
| 资源管控 | Resource Control | 第 6 章资源组 |
| SQL 性能诊断 | SQL Diagnosis | 第 6 章进阶 |
第 3 步,到「语句分析」里把刚才那几条 SQL 找回来。先故意制造负载再刷新(否则列表是空的):
SELECT COUNT(*) FROM t; -- 跑 20 次(或者用下面的循环一次制造多条)
SELECT a FROM t WHERE a > 0 ORDER BY a DESC; -- 带排序的,方便看 diff列表预期(列名与排序可能随版本微调,但维度不变):
SQL 摘要 执行次数 平均执行时间 总执行时间 扫行数 内存 CPU 时间 SQL 延迟
SELECT `count`(...) 20 0.8 ms 16 ms 3 0 0.5 ms 0.7 ms
SELECT `a` FROM ... 1 1.2 ms 1.2 ms 3 0 0.9 ms 1.1 ms第 4 步,点一行进去,把三个东西看完(这是第 6 章的预支):① 完整 SQL 样例(带真实参数);② 执行计划;③ 指标演进图(执行次数/延迟趋势)。试着把这里的计划与手动 EXPLAIN 的结果对一下,两边应该一致:
EXPLAIN SELECT COUNT(*) FROM t;
-- id | estRows | task | access object | operator info
-- StreamAgg_9 | 1.00 | root | | funcs:count(Column#4)->Column#3
-- └─TableReader_10 | 1.00 | root | | data:StreamAgg_8
-- └─StreamAgg_8 | 1.00 | cop[tikv] | | funcs:count(1)->Column#4
-- └─TableFullScan_7 | 3.00 | cop[tikv] | table:t | keep order:false
-- 注意:没跑过 ANALYZE 的新表,estRows 常与真值差得很远(第 6 章细讲)第 5 步,回到「拓扑」页确认第 1 题的结论:Dashboard 里能看到 1 个 TiDB、1 个 PD、1 个 TiKV、1 个 TiFlash,与 SHOW COMPONENTS 一致——以后忘了集群长什么样,先看拓扑再看大盘。
| 现象 | 原因 | 处理 |
|---|---|---|
访问 /dashboard 返回 404 或白屏 | 连到了 10080(TiDB 的状态页)而不是 2379 | 换 http://127.0.0.1:2379/dashboard |
| 页面要登录 | 集群开了 TLS + 客户端认证(生产常见) | 用部署时设的账号密码;若只配了 token,则用户名随意、密码填 authentication-token 的值 |
| 语句分析里空的 | 统计窗口没覆盖到,或刚执行完未上报(默认每 60s 一个采样点) | 多点几次刷新;或先查 information_schema.statements_summary |
| 想用命令而不是浏览器 | —— | SELECT digest_text, exec_count, avg_exec_time FROM information_schema.statements_summary ORDER BY avg_exec_time DESC LIMIT 5;(这就是「语句分析」背后的那张表,第 6 章重点用) |
