TiDB 用户手册
一、TiDB是什么
TiDB 是 PingCAP 公司设计的开源分布式 HTAP (Hybrid Transactional and Analytical Processing) 数据库,结合了传统的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB 的目标是为 OLTP (Online Transactional Processing) 和 OLAP (Online Analytical Processing) 场景提供一站式的解决方案。
TiDB 具备如下特性:
-
高度兼容 MySQL
大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移。
-
水平弹性扩展
通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景。
-
分布式事务
TiDB 100% 支持标准的 ACID 事务。
-
真正金融级高可用
相比于传统主从 (M-S) 复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可以实现故障的自动恢复 (auto-failover),无需人工介入。
-
一站式 HTAP 解决方案
TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合 TiSpark,可提供一站式 HTAP 解决方案,一份存储同时处理 OLTP & OLAP,无需传统繁琐的 ETL 过程。
-
云原生 SQL 数据库
TiDB 是为云而设计的数据库,支持公有云、私有云和混合云,使部署、配置和维护变得十分简单。
二、何时迁移TiDB。
TiDB与MySQL比较
与MySQL相比的优势
- 业务不用受限于MySQL单表大小限制,无需分表分库。
- 业务上可以无感扩容,可以随着集群的增长提升性能。
- 业务上可以在TiDB上进行海量数据少量分析功能。
与MySQL相比的劣势
- 机器成本相对较高,需要业务上进行评估。
- 与MySQL本身少量不同,会导致业务上需要适应TiDB的方式。
迁移TiDB的时机
- 当单表超过2000万,并且预计一年内至少能翻倍。
- 该大表为业务表,数据不能删除。
- 有相对复杂的数据分析需求时,并不想用到大数据去分析。
- 业务价值较高。
- 访问上没有明显的热点。
三、TiDB 迁移注意点
由于分布式数据库和单机数据库的差别,虽然TiDB已经能比较完整的支持MySQL语法,但是在内在机制还是有区别,所在进行迁移的时候需要注意的几点。
事物机制的区别
特别关注启用了Transaction事物,特别是依赖该事物中的update返回值是否成功的语句。要解决这个问题推荐使用select ..for update,或者是关闭数据库中的自动重试机制。
TiDB为乐观锁机制,而MySQL为悲观锁机制。会造成语义上的困扰。下表为例子,TiDB不会进行阻塞而是会新启一个事物进行重试。
session1 | session2 |
---|---|
begin; |
|
insert bill value (10,100,99); |
|
update account set balance set balance=99 where useId=10 and version=5; |
begin; |
commit; |
insert bill value (10,100,99); |
update account set balance set balance=99 where useId=10 and version=5; |
|
commit; |
|
session2.1 | |
begin; |
|
insert bill value (10,100,99); |
|
update account set balance set balance=99 where useId=10 and version=5; |
|
commit; |
自增 ID 连续性问题
推荐:尽量不使用数据库提供的自增id,严禁自增与自定义混用。
假设集群中有两个 tidb-server 实例 A 和 B(A 缓存 [1,30000] 的自增 ID,B 缓存 [30001,60000] 的自增 ID),依次执行如下操作:
- 客户端向 B 插入一条将
id
设置为 1 的语句insert into t values (1, 1)
,并执行成功。 - 客户端向 A 发送 Insert 语句
insert into t (c) (1)
,这条语句中没有指定id
的值,所以会由 A 分配,当前 A 缓存了 [1, 30000] 这段 ID,所以会分配 1 为自增 ID 的值,并把本地计数器加 1。而此时数据库中已经存在id
为 1 的数据,最终返回Duplicated Error
错误。
限制事物大小
每个事务的行数不超过 200 行,且单行数据小于 100k ,严禁大事物,长事物提交。
由于TiDB是分布式事物存储的过程采用的是二段提交,单个事物不能过程过大(这也是分布式系统的要求)。但是在对单体数据库的应用中往往会使用到例如:Delete * from t where xx
; 这种语句不能直接在TiDB中执行,或者通过TiDB中的设置会造成与MySQL不同的结果(TiDB会分批次delete,有可能有些成功有些失败)。
解决办法
-
添加 limit
Delete * from t where xx limit 5000;
-
循环操作。
- 截断时间方式
for i from 0 to 23: while affected_rows > 0: delete * from t where insert_time >= i:00:00 and insert_time < (i+1):00:00 limit 5000; affected_rows = select affected_rows()
- 有序ID最小值的方式
select min(id) minId from t where create_time > 'xx:xx:xx' and create_time < 'yy:yy:yy' ; select * from t where create_time > 'xx:xx:xx' and create_time < 'yy:yy:yy' id>=minId order by id limit 0,1000; while (select.size() != 0) { //do something max_id = select max_id(); select * from t where create_time > 'xx:xx:xx' and create_time < 'yy:yy:yy' id>=max_id order by id limit 0,1000; }
索引选择问题
相对复杂的索引选择建议手动指定索引,防止脱离索引的慢查询。每条复杂SQL必须检索引执行情况。
在TiDB选择上与MySQL有区别,由于单表的数据量过大,TiDB的统计信息更新不如MySQL及时,而且两者的优化有所不同,会造成在CBO过程中与MySQL中不一致。
如table中有索引如下:
index(bz_id,code,type)
执行以下语句时
select * from table where bz_id='s123' and code =32 and type = 12 order by id limit 1;
有可能会发生无法正确选对索引造成全表扫描的慢查询。
网友评论