TiDB试用 来源:TiDB  浏览 490 扫码 分享 2021-04-20 20:57:48

title: 使用 TiFlash

使用 TiFlash

TiFlash 部署完成后并不会自动同步数据,而需要手动指定需要同步的表。

用户可以使用 TiDB 或者 TiSpark 读取 TiFlash,TiDB 适合用于中等规模的 OLAP 计算,而 TiSpark 适合大规模的 OLAP 计算,用户可以根据自己的场景和使用习惯自行选择。具体参见:

按表构建 TiFlash 副本

TiFlash 接入 TiKV 集群后,默认不会开始同步数据。可通过 MySQL 客户端向 TiDB 发送 DDL 命令来为特定的表建立 TiFlash 副本:

  1. ALTER TABLE table_name SET TIFLASH REPLICA count

该命令的参数说明如下:

  • count 表示副本数,0 表示删除。

对于相同表的多次 DDL 命令,仅保证最后一次能生效。例如下面给出的操作 tpch50 表的两条 DDL 命令中,只有第二条删除副本的命令能生效:

为表建立 2 个副本:

  1. ALTER TABLE `tpch50`.`lineitem` SET TIFLASH REPLICA 2

删除副本:

  1. ALTER TABLE `tpch50`.`lineitem` SET TIFLASH REPLICA 0

注意事项:

  • 假设有一张表 t 已经通过上述的 DDL 语句同步到 TiFlash,则通过以下语句创建的表也会自动同步到 TiFlash:

    1. CREATE TABLE table_name like t
  • 如果集群版本 \< v4.0.6,若先对表创建 TiFlash 副本,再使用 TiDB Lightning 导入数据,会导致数据导入失败。需要在使用 TiDB Lightning 成功导入数据至表后,再对相应的表创建 TiFlash 副本。

  • 如果集群版本以及 TiDB Lightning 版本均 >= v4.0.6,无论一个表是否已经创建 TiFlash 副本,你均可以使用 TiDB Lightning 导入数据至该表。但注意此情况会导致 TiDB Lightning 导入数据耗费的时间延长,具体取决于 TiDB Lightning 部署机器的网卡带宽、TiFlash 节点的 CPU 及磁盘负载、TiFlash 副本数等因素。

  • 不推荐同步 1000 张以上的表,这会降低 PD 的调度性能。这个限制将在后续版本去除。

查看表同步进度

可通过如下 SQL 语句查看特定表(通过 WHERE 语句指定,去掉 WHERE 语句则查看所有表)的 TiFlash 副本的状态:

  1. SELECT * FROM information_schema.tiflash_replica WHERE TABLE_SCHEMA = '<db_name>' and TABLE_NAME = '<table_name>'

查询结果中:

  • AVAILABLE 字段表示该表的 TiFlash 副本是否可用。1 代表可用,0 代表不可用。副本状态为可用之后就不再改变,如果通过 DDL 命令修改副本数则会重新计算同步进度。
  • PROGRESS 字段代表同步进度,在 0.0~1.0 之间,1 代表至少 1 个副本已经完成同步。

使用 TiDB 读取 TiFlash

TiDB 提供三种读取 TiFlash 副本的方式。如果添加了 TiFlash 副本,而没有做任何 engine 的配置,则默认使用 CBO 方式。

智能选择

对于创建了 TiFlash 副本的表,TiDB 优化器会自动根据代价估算选择是否使用 TiFlash 副本。具体有没有选择 TiFlash 副本,可以通过 desc 或 explain analyze 语句查看,例如:

  1. desc select count(*) from test.t;
  1. +--------------------------+---------+--------------+---------------+--------------------------------+
  2. | id | estRows | task | access object | operator info |
  3. +--------------------------+---------+--------------+---------------+--------------------------------+
  4. | StreamAgg_9 | 1.00 | root | | funcs:count(1)->Column#4 |
  5. | └─TableReader_17 | 1.00 | root | | data:TableFullScan_16 |
  6. | └─TableFullScan_16 | 1.00 | cop[tiflash] | table:t | keep order:false, stats:pseudo |
  7. +--------------------------+---------+--------------+---------------+--------------------------------+
  8. 3 rows in set (0.00 sec)
  1. explain analyze select count(*) from test.t;
  1. +--------------------------+---------+---------+--------------+---------------+----------------------------------------------------------------------+--------------------------------+-----------+------+
  2. | id | estRows | actRows | task | access object | execution info | operator info | memory | disk |
  3. +--------------------------+---------+---------+--------------+---------------+----------------------------------------------------------------------+--------------------------------+-----------+------+
  4. | StreamAgg_9 | 1.00 | 1 | root | | time:83.8372ms, loops:2 | funcs:count(1)->Column#4 | 372 Bytes | N/A |
  5. | └─TableReader_17 | 1.00 | 1 | root | | time:83.7776ms, loops:2, rpc num: 1, rpc time:83.5701ms, proc keys:0 | data:TableFullScan_16 | 152 Bytes | N/A |
  6. | └─TableFullScan_16 | 1.00 | 1 | cop[tiflash] | table:t | time:43ms, loops:1 | keep order:false, stats:pseudo | N/A | N/A |
  7. +--------------------------+---------+---------+--------------+---------------+----------------------------------------------------------------------+--------------------------------+-----------+------+

cop[tiflash] 表示该任务会发送至 TiFlash 进行处理。如果没有选择 TiFlash 副本,可尝试通过 analyze table 语句更新统计信息后,再查看 explain analyze 结果。

需要注意的是,如果表仅有单个 TiFlash 副本且相关节点无法服务,智能选择模式下的查询会不断重试,需要指定 Engine 或者手工 Hint 来读取 TiKV 副本。

Engine 隔离

Engine 隔离是通过配置变量来指定所有的查询均使用指定 engine 的副本,可选 engine 为 “tikv”、”tidb” 和 “tiflash”(其中 “tidb” 表示 TiDB 内部的内存表区,主要用于存储一些 TiDB 系统表,用户不能主动使用),分别有 2 个配置级别:

  1. TiDB 实例级别,即 INSTANCE 级别。在 TiDB 的配置文件添加如下配置项:

    1. [isolation-read]
    2. engines = ["tikv", "tidb", "tiflash"]

    实例级别的默认配置为 ["tikv", "tidb", "tiflash"]

  2. 会话级别,即 SESSION 级别。设置语句:

    1. set @@session.tidb_isolation_read_engines = "逗号分隔的 engine list";

    或者

    1. set SESSION tidb_isolation_read_engines = "逗号分隔的 engine list";

    会话级别的默认配置继承自 TiDB 实例级别的配置。

最终的 engine 配置为会话级别配置,即会话级别配置会覆盖实例级别配置。比如实例级别配置了 “tikv”,而会话级别配置了 “tiflash”,则会读取 TiFlash 副本。当 engine 配置为 “tikv, tiflash”,即可以同时读取 TiKV 和 TiFlash 副本,优化器会自动选择。

注意:

由于 TiDB Dashboard 等组件需要读取一些存储于 TiDB 内存表区的系统表,因此建议实例级别 engine 配置中始终加入 “tidb” engine。

如果查询中的表没有对应 engine 的副本,比如配置了 engine 为 “tiflash” 而该表没有 TiFlash 副本,则查询会报该表不存在该 engine 副本的错。

手工 Hint

手工 Hint 可以在满足 engine 隔离的前提下,强制 TiDB 对于某张或某几张表使用指定的副本,使用方法为:

  1. select /*+ read_from_storage(tiflash[table_name]) */ ... from table_name;

如果在查询语句中对表设置了别名,在 Hint 语句中必须使用别名才能使 Hint 生效。比如:

  1. select /*+ read_from_storage(tiflash[alias_a,alias_b]) */ ... from table_name_1 as alias_a, table_name_2 as alias_b where alias_a.column_1 = alias_b.column_2;

其中 tiflash[] 是提示优化器读取 TiFlash 副本,亦可以根据需要使用 tikv[] 来提示优化器读取 TiKV 副本。更多关于该 Hint 语句的语法可以参考 READ_FROM_STORAGE

如果 Hint 指定的表在指定的引擎上不存在副本,则 Hint 会被忽略,并产生 warning。另外 Hint 必须在满足 engine 隔离的前提下才会生效,如果 Hint 中指定的引擎不在 engine 隔离列表中,Hint 同样会被忽略,并产生 warning。

注意:

MySQL 命令行客户端在 5.7.7 版本之前默认清除了 Optimizer Hints。如果需要在这些早期版本的客户端中使用 Hint 语法,需要在启动客户端时加上 --comments 选项,例如 mysql -h 127.0.0.1 -P 4000 -uroot --comments

三种方式之间关系的总结

上述三种读取 TiFlash 副本的方式中,Engine 隔离规定了总的可使用副本 engine 的范围,手工 Hint 可以在该范围内进一步实现语句级别及表级别的细粒度的 engine 指定,最终由 CBO 在指定的 engine 范围内根据代价估算最终选取某个 engine 上的副本。

注意:

TiDB 4.0.3 版本之前,在非只读 SQL 语句中(比如 INSERT INTO ... SELECTSELECT ... FOR UPDATEUPDATE ...DELETE ...)读取 TiFlash,行为是未定义。TiDB 4.0.3 以及后续的版本,TiDB 内部会对非只读 SQL 语句忽略 TiFlash 副本以保证数据写入、更新、删除的正确性。对应的,如果使用了智能选择的方式,TiDB 会自动选择非 TiFlash 副本;如果使用了 Engine 隔离的方式指定读取 TiFlash 副本,则查询会报错;而如果使用了手工 Hint 的方式,则 Hint 会被忽略。

使用 TiSpark 读取 TiFlash

TiSpark 目前提供类似 TiDB 中 engine 隔离的方式读取 TiFlash,方式是通过配置参数 spark.tispark.isolation_read_engines。参数值默认为 tikv,tiflash,表示根据 CBO 自动选择从 TiFlash 或从 TiKV 读取数据。如果将该参数值设置成 tiflash,表示强制从 TiFlash 读取数据。

注意:

设为 true 时,所有查询的表都会只读取 TiFlash 副本,设为 false 则只读取 TiKV 副本。设为 true 时,要求查询所用到的表都必须已创建了 TiFlash 副本,对于未创建 TiFlash 副本的表的查询会报错。

可以使用以下任意一种方式进行设置:

  1. 在 spark-defaults.conf 文件中添加:

    1. spark.tispark.isolation_read_engines tiflash
  2. 在启动 Spark shell 或 Thrift server 时,启动命令中添加 --conf spark.tispark.isolation_read_engines=tiflash

  3. Spark shell 中实时设置:spark.conf.set("spark.tispark.isolation_read_engines", "tiflash")

  4. Thrift server 通过 beeline 连接后实时设置:set spark.tispark.isolation_read_engines=tiflash

TiFlash 支持的计算下推

TiFlash 支持部分算子的下推,支持的算子如下:

  • TableScan:该算子从表中读取数据
  • Selection:该算子对数据进行过滤
  • HashAgg:该算子基于 Hash Aggregation 算法对数据进行聚合运算
  • StreamAgg:该算子基于 Stream Aggregation 算法对数据进行聚合运算。StreamAgg 仅支持不带 GROUP BY 条件的列。
  • TopN:该算子对数据求 TopN 运算
  • Limit:该算子对数据进行 limit 运算
  • Project:该算子对数据进行投影运算
  • HashJoin:该算子基于 Hash Join 算法对数据进行连接运算,但有以下使用条件:
    • 只有在 MPP 模式下才能被下推
    • 必须带有等值的 join 条件
    • 不支持下推 Full Outer Join

在 TiDB 中,算子之间会呈现树型组织结构。一个算子能下推到 TiFlash 的前提条件,是该算子的所有子算子都能下推到 TiFlash。因为大部分算子都包含有表达式计算,当且仅当一个算子所包含的所有表达式均支持下推到 TiFlash 时,该算子才有可能下推给 TiFlash。目前 TiFlash 支持下推的表达式包括:

  1. +, -, /, *, >=, <=, =, !=, <, >, ifnull, isnull, bitor, in, bitand, or, and, like, not, case when, month, substr, timestampdiff, date_format, from_unixtime, json_length, if, bitneg, bitxor,
  2. round without fraction, cast(int as decimal), date_add(datetime, int), date_add(datetime, string), min, max, sum, count, avg, approx_count_distinct

其中,cast 和 date_add 的下推默认不开启,若需要手动开启,请参考优化规则及表达式下推的黑名单

另外,所有包含 Time/Bit/Set/Enum/Geometry 类型的表达式均不能下推到 TiFlash。

如查询遇到不支持的下推计算,则需要依赖 TiDB 完成剩余计算,可能会很大程度影响 TiFlash 加速效果。对于暂不支持的算子/表达式,将会在后续版本中陆续提供支持,也可以联系官方沟通。

使用 MPP 模式

TiFlash 支持 MPP 模式的查询执行,即在计算中引入跨节点的数据交换(data shuffle 过程)。MPP 模式默认开启,如需关闭可将全局/会话变量 tidb_allow_mpp 的值设为 0 或 OFF

  1. set @@session.tidb_allow_mpp=0

MPP 模式目前支持的物理算法有:Broadcast Hash Join、Shuffled Hash Join 和 Shuffled Hash Aggregation。算法的选择由优化器自动判断。通过 EXPLAIN 语句可以查看具体的查询执行计划。

以 TPC-H 测试集中的表结构为例:

  1. mysql> explain select count(*) from customer c join nation n on c.c_nationkey=n.n_nationkey;
  2. +------------------------------------------+------------+-------------------+---------------+----------------------------------------------------------------------------+
  3. | id | estRows | task | access object | operator info |
  4. +------------------------------------------+------------+-------------------+---------------+----------------------------------------------------------------------------+
  5. | HashAgg_23 | 1.00 | root | | funcs:count(Column#16)->Column#15 |
  6. | └─TableReader_25 | 1.00 | root | | data:ExchangeSender_24 |
  7. | └─ExchangeSender_24 | 1.00 | batchCop[tiflash] | | ExchangeType: PassThrough |
  8. | └─HashAgg_12 | 1.00 | batchCop[tiflash] | | funcs:count(1)->Column#16 |
  9. | └─HashJoin_17 | 3000000.00 | batchCop[tiflash] | | inner join, equal:[eq(tpch.nation.n_nationkey, tpch.customer.c_nationkey)] |
  10. | ├─ExchangeReceiver_21(Build) | 25.00 | batchCop[tiflash] | | |
  11. | │ └─ExchangeSender_20 | 25.00 | batchCop[tiflash] | | ExchangeType: Broadcast |
  12. | │ └─TableFullScan_18 | 25.00 | batchCop[tiflash] | table:n | keep order:false |
  13. | └─TableFullScan_22(Probe) | 3000000.00 | batchCop[tiflash] | table:c | keep order:false |
  14. +------------------------------------------+------------+-------------------+---------------+----------------------------------------------------------------------------+
  15. 9 rows in set (0.00 sec)

在执行计划中,出现了 ExchangeReceiver 和 ExchangeSender 算子。该执行计划表示 nation 表读取完毕后,经过 ExchangeSender 算子广播到各个节点中,与 customer 表先后进行 HashJoin 和 HashAgg 操作,再将结果返回至 TiDB 中。

TiFlash 提供了两个全局/会话变量决定是否选择 Broadcast Hash Join,分别为:

  • tidb_broadcast_join_threshold_size,单位为 bytes。如果表大小(字节数)小于该值,则选择 Broadcast Hash Join 算法。否则选择 Shuffled Hash Join 算法。
  • tidb_broadcast_join_threshold_count,单位为行数。如果 join 的对象为子查询,优化器无法估计子查询结果集大小,在这种情况下通过结果集行数判断。如果子查询的行数估计值小于该变量,则选择 Broadcast Hash Join 算法。否则选择 Shuffled Hash Join 算法。

注意事项

TiFlash 目前尚不支持的一些功能,与原生 TiDB 可能存在不兼容的问题,具体如下:

  • TiFlash 计算层:

    • 不支持检查溢出的数值。例如将两个 BIGINT 类型的最大值相加 9223372036854775807 + 9223372036854775807,该计算在 TiDB 中预期的行为是返回错误 ERROR 1690 (22003): BIGINT value is out of range,但如果该计算在 TiFlash 中进行,则会得到溢出的结果 -2 且无报错。
    • 不支持窗口函数。
    • 不支持从 TiKV 读取数据。
    • 目前 TiFlash 中的 sum 函数不支持传入字符串类型的参数,但 TiDB 在编译时无法检测出这种情况。所以当执行类似于 select sum(string_col) from t 的语句时,TiFlash 会报错 [FLASH:Coprocessor:Unimplemented] CastStringAsReal is not supported.。要避免这类报错,需要手动把 SQL 改写成 select sum(cast(string_col as double)) from t
    • TiFlash 目前的 Decimal 除法计算和 TiDB 存在不兼容的情况。例如在进行 Decimal 相除的时候,TiFlash 会始终按照编译时推断出来的类型进行计算,而 TiDB 则在计算过程中采用精度高于编译时推断出来的类型。这导致在一些带有 Decimal 除法的 SQL 语句在 TiDB + TiKV 上的执行结果会和 TiDB + TiFlash 上的执行结果不一样,示例如下:

      1. mysql> create table t (a decimal(3,0), b decimal(10, 0));
      2. Query OK, 0 rows affected (0.07 sec)
      3. mysql> insert into t values (43, 1044774912);
      4. Query OK, 1 row affected (0.03 sec)
      5. mysql> alter table t set tiflash replica 1;
      6. Query OK, 0 rows affected (0.07 sec)
      7. mysql> set session tidb_isolation_read_engines='tikv';
      8. Query OK, 0 rows affected (0.00 sec)
      9. mysql> select a/b, a/b + 0.0000000000001 from t where a/b;
      10. +--------+-----------------------+
      11. | a/b | a/b + 0.0000000000001 |
      12. +--------+-----------------------+
      13. | 0.0000 | 0.0000000410001 |
      14. +--------+-----------------------+
      15. 1 row in set (0.00 sec)
      16. mysql> set session tidb_isolation_read_engines='tiflash';
      17. Query OK, 0 rows affected (0.00 sec)
      18. mysql> select a/b, a/b + 0.0000000000001 from t where a/b;
      19. Empty set (0.01 sec)

      以上示例中,在 TiDB 和 TiFlash 中,a/b 在编译期推导出来的类型都为 Decimal(7,4),而在 Decimal(7,4) 的约束下,a/b 返回的结果应该为 0.0000。但是在 TiDB 中,a/b 运行期的精度比 Decimal(7,4) 高,所以原表中的数据没有被 where a/b 过滤掉。而在 TiFlash 中 a/b 在运行期也是采用 Decimal(7,4) 作为结果类型,所以原表中的数据被 where a/b 过滤掉了。

  • TiFlash MPP 模式不支持如下功能:

    • 不支持分区表,对于带有分区表的查询默认不选择 MPP 模式。
    • 在配置项 new_collations_enabled_on_first_bootstrap 的值为 true 时,MPP 不支持 join 的连接键类型为字符串或 group by 聚合运算时列类型为字符串的情况。在处理这两类查询时,默认不选择 MPP 模式。

[转帖]使用 TiFlash的更多相关文章

  1. nginx负载均衡基于ip_hash的session粘帖

    nginx负载均衡基于ip_hash的session粘帖 nginx可以根据客户端IP进行负载均衡,在upstream里设置ip_hash,就可以针对同一个C类地址段中的客户端选择同一个后端服务器,除 ...

  2. [转帖]网络协议封封封之Panabit配置文档

    原帖地址:http://myhat.blog.51cto.com/391263/322378

  3. [转帖]零投入用panabit享受万元流控设备——搭建篇

    原帖地址:http://net.it168.com/a2009/0505/274/000000274918.shtml 你想合理高效的管理内网流量吗?你想针对各个非法网络应用与服务进行合理限制吗?你是 ...

  4. 3d数学总结帖

    3d数学总结帖,以下是对3d学习过程中数学知识的简单总结 角度值和弧度制的互转 Deg2Rad 角度A1转弧度A2 => A2=A1*PI/180 Rad2Deg 弧度A2转换角度A1 => ...

  5. [转帖]The Lambda Calculus for Absolute Dummies (like myself)

    Monday, May 7, 2012 The Lambda Calculus for Absolute Dummies (like myself)   If there is one highly ...

  6. [转帖]FPGA开发工具汇总

    原帖:http://blog.chinaaet.com/yocan/p/5100017074 ----------------------------------------------------- ...

  7. [Android分享] 【转帖】Android ListView的A-Z字母排序和过滤搜索功能

      感谢eoe社区的分享   最近看关于Android实现ListView的功能问题,一直都是小伙伴们关心探讨的Android开发问题之一,今天看到有关ListView实现A-Z字母排序和过滤搜索功能 ...

  8. AxureRP7.0各类交互效果汇总帖(转)

    了便于大家参考,我把这段时间发布分享的所有关于AxureRP7.0的原型做了整理. 以下资源均有对应的RP源文件可以下载. 当然 ,其中有部分是需要通过完成解密游戏[攻略]才能得到下载地址或者下载密码 ...

  9. 未能加载文件或程序集“Newtonsoft.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=30a [问题点数:40分,结帖人u010259408]

    未能加载文件或程序集“Newtonsoft.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=30a [问题点数:40分,结帖人u01025 ...

  10. 转帖-[教程] Win7精简教程(简易中度)2016年8月-0day

    [教程] Win7精简教程(简易中度)2016年8月 0day 发表于 2016-8-19 16:08:41  https://www.itsk.com/thread-370260-1-1.html ...

随机推荐

  1. 文心一言 VS 讯飞星火 VS chatgpt (49)-- 算法导论6.2 1题

    一.参照图6-2的方法,说明 MAX-HEAPIFY(A,3)在数组 A=(27,17,3,16,13,10,1,5,7,12,4,8,9,0)上的操作过程. 文心一言: 下面是 MAX-HEAPIF ...

  2. 2023-05-28:为什么Redis单线程模型效率也能那么高?

    2023-05-28:为什么Redis单线程模型效率也能那么高? 答案2023-05-28: 1.C语言实现,效率高 C语言程序运行速度快,因为其相较于其他高级语言更加接近底层机器.由于C语言直接操作 ...

  3. 使用bind搭建内网dns服务

    dns服务端方案简介 dns服务有什么用呢,尤其是内网的dns服务,其实用处还蛮大的,我见过的典型使用,是数据库跨机房多活. 如某mysql主机搭建在深圳机房,为了保证高可用,那我们可以给这台主库,维 ...

  4. Caffeine Cache缓存

    SpringBoot 集成 Caffeine Caffeine 和 Spring Cache 依赖,使用注解方法实现缓存 依赖 <!--提供 Spring Boot 中的缓存支持--> & ...

  5. MySQL进阶篇:详解索引使用_最左前缀法则

    MySQL进阶篇:第四章_四.一_ 索引使用_最左前缀法则 最左前缀法则 如果索引了多列(联合索引),要遵守最左前缀法则.最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列.如果跳跃某一列 ...

  6. 理解三值逻辑与NULL,你离SQL高手更近了一步

    什么是NULL NULL 用于表示缺失的值或遗漏的未知数据,不是某种具体类型的值.数据表中的 NULL 值表示该值所处的字段为空,值为 NULL 的字段没有值,尤其要明白的是:NULL 值与 0 或者 ...

  7. HBuilderX获取iOS证书的打包步骤

    简介: 目前app开发,很多企业都用H5框架来开发,而uniapp又是这些h5框架里面最成熟的,因此hbuilderx就成为了开发者的首选.然而,打包APP是需要证书的,那么这个证书又是如何获得呢? ...

  8. 用 Java?就用国产轻量框架: Solon v1.10.2

    相对于 Spring Boot 和 Spring Cloud 的项目: 启动快 5 - 10 倍. (更快) qps 高 2- 3 倍. (更高) 运行时内存节省 1/3 ~ 1/2. (更少) 打包 ...

  9. 无法获得数据库 'model' 上的排他锁。请稍后重试该操作

    标题: Microsoft SQL Server Management Studio 数据库 "XXXX" 的 创建 失败. (Microsoft.SqlServer.Smo) 有 ...

  10. 你正在调试XXX的发布版本,如果在启用 仅我的代码 的同时,使用通过编译器优化的发布版本

    仅我的代码"警告 你正在调试 XXX.dll 的发布版本.如果在启用"仅我的代码"的同时使用通过编译器优化的发布版本,调试体验会降级(例如,将不会命中断点) 停止调试禁用 ...