黄东旭解析 TiDB 的核心优势
632
2023-11-24
对于 OLTP 场景,程序发送给数据库的 SQL 语句在去除参数变化后都是可穷举的某几类。因此建议使用预处理 语句 (Prepared Statements) 代替普通的文本执行,并复用预处理语句来直接执行,从而避免 TiDB 重复解析和生 成 SQL 执行计划的开销。
useServerPrepStmts = true cachePrepStmts = true useConfigs = maxPerformance #最优性能配置,包含cachePrepStmts = true注:因为一个客户端bug,批量更新时如果要配置rewriteBatchedStatements = true和useServerPrepStmts ,→ = true,推荐同时配置 allowMultiQueries = true 参数来避免这个 bug
设置 FetchSize 为 Integer.MIN_VALUE 让客户端不缓存,客户端通过 StreamingResult 的方式从网络连接上流 式读取执行结果。
使用 Cursor Fetch,首先需设置 FetchSize 为正整数,且在 JDBC URL 中配置 useCursorFetch = true。
注:推荐使用第一种将 FetchSize 设置为 Integer.MIN_VALUE 的方式,比第二种功能 实现更简单且执行效率更高。
Primary Key: 即主键索引,即标识在主键列上的索引
Primary Key 的定义为:唯一,不为空。
不保证为聚簇索引,由另一组 关键字 CLUSTERED、NONCLUSTERED 额外控制 Primary Key 是否为聚簇索引,若不指定,则由系统 变量 @@global.tidb_enable_clustered_index 影响
Secondary Index: 即二级索引,即在非主键上标识的索引
聚簇索引:(索引组织表)
主键列数据(键)- 行数据(值)
非聚簇索引:
_tidb_rowid(键)- 行数据(值)
主键列数据(键)- _tidb_rowid(值)
一个表可以没有主键,主键也可以是非整数类型。但此时 TiDB 就会创建一个tidb_rowid 作为隐式主键。隐式主键 tidb_rowid 因为其单调递增的特性,可能在大批量写入场景下会导致写入热点,如果你写入量密集, 可考虑通过SHARD_ROW_ID_BITS 和PRE_SPLIT_REGIONS 两参数控制打散。但这可能导致读放大,请自行取舍。 表的主键为整数类型且使用了 AUTO_INCREMENT 时,无法使用 SHARD_ROW_ID_BITS 消除热点。需解决此热点问 题,且无需使用主键的连续和递增时,可使用AUTO_RANDOM 替换 AUTO_INCREMENT 属性来消除行 ID 的连续性。
本地临时表:表定义和表内数据只对当前会话可见,适用于暂存会话内的中间数据
本地临时表会在会话结束后连同数据和表结构都进行自动清理
全局临时表:全局临时表的表定义对整个 TiDB 集群可见,表内数据只对当前事务可见,适用于暂存事务内的中间数 据
全局临时表在事务结束后会自动清除数据,但是表结构依然保留,需要手动删除。
在仅有一个唯一键的表上使用 INSERT ON DUPLICATE KEY UPDATE。此语句在检测到任何 唯一键 (包括主 键) 冲突时,将更新数据。在不止匹配到一行冲突时,将只会一行数据。因此,除非能保证仅有一行冲 突,否则不建议在有多个唯一键的表中使用 INSERT ON DUPLICATE KEY UPDATE 语句。
你需要更新大量行 (数万或更多) 的时候,建议使用一个迭代,每次都只更新一部分数据,直到更新全 部完成。这是因为 TiDB 单个事务大小限制为txn-total-size-limit(默认为 100MB),且一次性过多的数据更新,将 导致持有锁时间过长(悲观事务),或产生大量冲突(乐观事务)。你可以在程序或脚本中使用循环来完成操 作。
限制为txn-total-size-limit (默认为 100MB)
如果你需要删除表内的所有数据,请勿使用 DELETE 语句,而应该使用TRUNCATE 语句。
DELETE 语句运行之后 TiDB 并非立刻删除数据,而是将这些数据标记为可删除。然后等待 TiDB GC (Garbage Collection) 来清理不再需要的旧数据。因此,你的 DELETE 语句并不会立即减少磁盘用量。
在大批量的数据删除之后,很有可能会导致索引选择不准确的 情况发生。你可以使用手动收集的办法,更新统计信息。
TiDB 从 v6.1.0 版本开始支持非事务 DML 语句特性。非事务性删除可以提高性能。
使用 TTL (Time to Live) 定期删除过期数据(使用场景)
定期删除验证码、短网址记录
定期删除不需要的历史订单
自动删除计算的中间结果
不允许在临时表上设置 TTL 属性
不保证所有过期数据立即被删除,过期数据被删除的时间取决于后台清理任务的调度周期和调度窗口
和 MySQL 一样,TIMESTAMP 数据类型受 2038 年问题的影响。如果存储的值大于 2038,建 议使用 DATETIME 类型。
在MySQL中,TIMESTAMP数据类型使用4字节来存储时间,这导致其能表示的时间范围有限,最大只能到2038年1月19日03:14:07(UTC)。这就是所谓的"2038年问题"或"Y2K38问题"。
与TIMESTAMP不同,DATETIME不受2038年问题的影响,它使用8字节存储日期和时间,可以表示从1000年1月1日00:00:00到9999年12月31日23:59:59的时间范围。
预处理语句是一种将多个仅有参数不同的 SQL语句进行模板化的语句,它让 SQL 语句与参数进行了分离
避免sql注入风险
提高sql执行性能
应用程序中sql语句是可以枚举的,所以预处理语句是最佳实践之一
通用场景的JDBC 连接字符串配置:jdbc:mysql://127.0.0.1:4000/test?user=root&useConfigs=maxPerformance&useServerPrepStmts=true&prepStmtCacheSqlLimit=2048&prepStmtCacheSize=256&rewriteBatchedStatements=true&allowMultiQueries=true
一个临时的中间结果集,能够在 SQL 语句中引用多次,提高 SQL 语句的可读性与执行效 率
实现了快照隔离 (Snapshot Isolation, SI) 级别的一致性
TiDB 支持的隔离级别是 RC( Read Committed)与 SI( Snapshot Isolation),其中 SI 与 RR( Repeatable Read)隔离级别基本等价
SI 可以克服幻读,但 ANSI/ISO SQL 标准中的 RR 不能。
SI 不能克服写偏斜
支持的最大单个事务容量为 10GB
最大单行记录容量为 120MB
为了使性能达到最优,建议每 100 ~ 500 行写入一个事务。
使用单个语句多行数据操作
使用 PREPARE
避免查询不必要的信息
使用批量删除
使用批量更新
使用 TRUNCATE 语句代替 DELETE 全表数据
建立你需要使用的数据的所有列的组合索引,这种优化技巧被称为覆盖索引优化 (covering index optimization)。
区分度比较大的列,通过索引能显著地减少过滤后的行数。
有多个查询条件时,可以选择组合索引,注意需要把等值条件的列放在组合索引的前面
使用组合索引时,需要满足最左前缀原则
在查询条件中使用索引列作为条件时,不要在索引列上做计算,函数,或者类型转换的操作,会导致 优化器无法使用该索引。
尽量使用覆盖索引,即索引列包含查询列,避免总是 SELECT * 查询所有列的语句。
查询条件使用 !=, NOT IN 时,无法使用索引。
使用 LIKE 时如果条件是以通配符 % 开头,也无法使用索引
隐式类型转换会导致: • 索引失效 • 精度丢失
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。