📣

TiDB Cloud Serverless 现已更名为
Starter
!此页面由 AI 自动翻译,英文原文请见
此处。

HTAP 查询

HTAP 代表混合事务与分析处理(Hybrid Transactional and Analytical Processing)。传统上,数据库通常为事务场景或分析场景设计,因此数据平台常常需要拆分为事务处理(Transactional Processing)和分析处理(Analytical Processing),并将数据从事务数据库复制到分析数据库,以快速响应分析查询。TiDB 数据库可以同时执行事务和分析任务,这极大简化了数据平台的构建,并允许用户使用更新更快的数据进行分析。

TiDB 使用 TiKV,基于行的存储引擎,进行在线事务处理(OLTP);同时使用 TiFlash,基于列的存储引擎,进行在线分析处理(OLAP)。行存储引擎和列存储引擎共存于 HTAP 中。两者都能自动复制数据并保持强一致性。行存储引擎优化 OLTP 性能,列存储引擎优化 OLAP 性能。

创建表 小节介绍了如何启用 TiDB 的 HTAP 功能。以下内容描述了如何利用 HTAP 更快地进行数据分析。

数据准备

在开始之前,你可以通过 tiup demo 命令 导入更多示例数据。例如:

tiup demo bookshop prepare --users=200000 --books=500000 --authors=100000 --ratings=1000000 --orders=1000000 --host 127.0.0.1 --port 4000 --drop-tables

或者,你也可以 使用 TiDB Cloud 的导入功能 导入预先准备好的示例数据。

窗口函数

在使用数据库时,除了存储数据和提供应用功能(如排序和评分图书)之外,你可能还需要在数据库中分析数据,以进行后续操作和决策。

从单个表查询数据 文档介绍了如何使用聚合查询对数据进行整体分析。在更复杂的场景中,你可能希望将多个聚合查询的结果合并成一个查询。如果你想了解某本书的历史订单金额趋势,可以对每个月的所有订单数据进行 sum 聚合,然后将这些 sum 结果合并,得到历史趋势。

为了方便此类分析,自 TiDB v3.0 起,TiDB 支持窗口函数。该函数为每一行数据提供跨多行访问数据的能力。不同于普通的聚合查询,窗口函数在聚合行时不会将结果集合并成单行。

与聚合函数类似,使用窗口函数时也需要遵循固定的语法:

SELECT window_function() OVER ([partition_clause] [order_clause] [frame_clause]) AS alias FROM table_name

ORDER BY 子句

利用聚合窗口函数 sum(),你可以分析某本书的历史订单金额趋势。例如:

WITH orders_group_by_month AS ( SELECT DATE_FORMAT(ordered_at, '%Y-%c') AS month, COUNT(*) AS orders FROM orders WHERE book_id = 3461722937 GROUP BY 1 ) SELECT month, SUM(orders) OVER(ORDER BY month ASC) as acc FROM orders_group_by_month ORDER BY month ASC;

sum() 函数会根据 OVER 子句中的 ORDER BY 指定的顺序累加数据。结果如下:

+---------+-------+ | month | acc | +---------+-------+ | 2011-5 | 1 | | 2011-8 | 2 | | 2012-1 | 3 | | 2012-2 | 4 | | 2013-1 | 5 | | 2013-3 | 6 | | 2015-11 | 7 | | 2015-4 | 8 | | 2015-8 | 9 | | 2017-11 | 10 | | 2017-5 | 11 | | 2019-5 | 13 | | 2020-2 | 14 | +---------+-------+

通过时间作为横轴、累计订单金额作为纵轴,用折线图可直观展示该书的历史订单趋势,坡度的变化反映了订单量的变化。

PARTITION BY 子句

假设你想分析不同类型图书的历史订单趋势,并在同一折线图中显示多个系列。

你可以使用 PARTITION BY 子句,将图书按类型分组,分别统计每个类型的历史订单。

WITH orders_group_by_month AS ( SELECT b.type AS book_type, DATE_FORMAT(ordered_at, '%Y-%c') AS month, COUNT(*) AS orders FROM orders o LEFT JOIN books b ON o.book_id = b.id WHERE b.type IS NOT NULL GROUP BY book_type, month ), acc AS ( SELECT book_type, month, SUM(orders) OVER(PARTITION BY book_type ORDER BY book_type, month ASC) as acc FROM orders_group_by_month ORDER BY book_type, month ASC ) SELECT * FROM acc;

结果示例:

+------------------------------+---------+------+ | book_type | month | acc | +------------------------------+---------+------+ | Magazine | 2011-10 | 1 | | Magazine | 2011-8 | 2 | | Magazine | 2012-5 | 3 | | Magazine | 2013-1 | 4 | | Magazine | 2013-6 | 5 | ... | Novel | 2011-3 | 13 | | Novel | 2011-4 | 14 | | Novel | 2011-6 | 15 | | Novel | 2011-8 | 17 | | Novel | 2012-1 | 18 | | Novel | 2012-2 | 20 | ... | Sports | 2021-4 | 49 | | Sports | 2021-7 | 50 | | Sports | 2022-4 | 51 | +------------------------------+---------+------+ 1500 rows in set (1.70 sec)

非聚合窗口函数

TiDB 还提供一些非聚合的 窗口函数,用于更丰富的分析。

例如,分页查询 文档介绍了如何使用 row_number() 函数实现高效分页批量处理。

混合工作负载

在使用 TiDB 进行实时在线分析处理(HTAP)场景下的混合负载时,你只需提供 TiDB 的入口点,TiDB 会根据具体业务自动选择不同的处理引擎。

创建 TiFlash 副本

TiDB 默认使用基于行的存储引擎 TiKV。若要使用列存储引擎 TiFlash,详见 启用 HTAP 功能。在通过 TiFlash 查询数据之前,需要为 booksorders 表创建 TiFlash 副本,使用以下语句:

ALTER TABLE books SET TIFLASH REPLICA 1; ALTER TABLE orders SET TIFLASH REPLICA 1;

你可以用以下语句检查 TiFlash 副本的进度:

SELECT * FROM information_schema.tiflash_replica WHERE TABLE_SCHEMA = 'bookshop' and TABLE_NAME = 'books'; SELECT * FROM information_schema.tiflash_replica WHERE TABLE_SCHEMA = 'bookshop' and TABLE_NAME = 'orders';

PROGRESS 列为 1 表示进度已达 100%,AVAILABLE 列为 1 表示副本当前可用。

+--------------+------------+----------+---------------+-----------------+-----------+----------+ | TABLE_SCHEMA | TABLE_NAME | TABLE_ID | REPLICA_COUNT | LOCATION_LABELS | AVAILABLE | PROGRESS | +--------------+------------+----------+---------------+-----------------+-----------+----------+ | bookshop | books | 143 | 1 | | 1 | 1 | +--------------+------------+----------+---------------+-----------------+-----------+----------+ 1 row in set (0.07 sec) +--------------+------------+----------+---------------+-----------------+-----------+----------+ | TABLE_SCHEMA | TABLE_NAME | TABLE_ID | REPLICA_COUNT | LOCATION_LABELS | AVAILABLE | PROGRESS | +--------------+------------+----------+---------------+-----------------+-----------+----------+ | bookshop | orders | 147 | 1 | | 1 | 1 | +--------------+------------+----------+---------------+-----------------+-----------+----------+ 1 row in set (0.07 sec)

副本创建完成后,可以使用 EXPLAIN 语句检查上述窗口函数 PARTITION BY 子句 的执行计划。如果在执行计划中出现 cop[tiflash],表示 TiFlash 引擎已开始工作。

然后,再次执行 PARTITION BY 子句 中的示例 SQL 语句,结果如下:

+------------------------------+---------+------+ | book_type | month | acc | +------------------------------+---------+------+ | Magazine | 2011-10 | 1 | | Magazine | 2011-8 | 2 | | Magazine | 2012-5 | 3 | | Magazine | 2013-1 | 4 | | Magazine | 2013-6 | 5 | ... | Novel | 2011-3 | 13 | | Novel | 2011-4 | 14 | | Novel | 2011-6 | 15 | | Novel | 2011-8 | 17 | | Novel | 2012-1 | 18 | | Novel | 2012-2 | 20 | ... | Sports | 2021-4 | 49 | | Sports | 2021-7 | 50 | | Sports | 2022-4 | 51 | +------------------------------+---------+------+ 1500 rows in set (0.79 sec)

通过对比两次执行结果,可以发现使用 TiFlash 后查询速度显著提升(数据量大的情况下提升更明显)。这是因为窗口函数通常依赖全表扫描某些列,而列存的 TiFlash 更适合处理此类分析任务。对于 TiKV,如果使用主键或索引减少查询行数,查询速度也会很快,且资源消耗少于 TiFlash。

指定查询引擎

TiDB 使用基于成本的优化器(CBO)根据成本估算自动选择是否使用 TiFlash 副本。但如果你确定查询是事务性还是分析性的,可以通过 优化器提示 指定使用的查询引擎。

要在查询中指定使用的引擎,可以使用 /*+ read_from_storage(engine_name[table_name]) */ 提示,如下所示。

WITH orders_group_by_month AS ( SELECT /*+ read_from_storage(tikv[o]) */ b.type AS book_type, DATE_FORMAT(ordered_at, '%Y-%c') AS month, COUNT(*) AS orders FROM orders o LEFT JOIN books b ON o.book_id = b.id WHERE b.type IS NOT NULL GROUP BY book_type, month ), acc AS ( SELECT book_type, month, SUM(orders) OVER(PARTITION BY book_type ORDER BY book_type, month ASC) as acc FROM orders_group_by_month mo ORDER BY book_type, month ASC ) SELECT * FROM acc;

你可以用 EXPLAIN 语句检查上述 SQL 的执行计划。如果在任务列中同时出现 cop[tiflash]cop[tikv],表示 TiFlash 和 TiKV 都在调度完成此查询。注意,TiFlash 和 TiKV 存储引擎通常使用不同的 TiDB 节点,因此两者的查询类型不会相互影响。

关于 TiDB 如何选择使用 TiFlash 的更多信息,请参见 使用 TiDB 读取 TiFlash 副本

阅读更多

需要帮助?

DiscordSlack 社区提问,或 提交支持工单

文档内容是否有帮助?