PolarDB-X性能优化之利用广播表优化join操作

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 正确的使用PolarDB-X中的广播表特性可以将join操作下推到存储节点执行,提高sql的执行效率

PolarDB-X的主要用途是水平分表,在水平分表中,有些表只有少量数据,如果创建成普通的单表,在同大表join时,会导致join不能下推到存储节点,只能在计算节点执行,join、sort之类的操作如果在计算节点执行,不但会导致计算节点负载过重,也会导致大量数据在计算和存储节点之间传输,影响集群的性能。如果将此类小表创建成广播表,PolarDB-X就可以将join操作下推到存储节点执行,从而大幅度提高性能。简单测试一下就可以看出来。

1 集群中已有下面的测试表

MySQL [test]> show create table dept;

+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| TABLE | CREATE TABLE                                                                                                                                                                                    |

+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| dept  | CREATE TABLE `dept` (

       `dept_no` tinyint(4) NOT NULL,

       `dept_name` varchar(20) DEFAULT NULL,

       `loc` varchar(30) DEFAULT NULL,

       PRIMARY KEY (`dept_no`)

) ENGINE = InnoDB DEFAULT CHARSET = utf8 |

+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 row in set (0.04 sec)

MySQL [test]> show create table emp;

+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| TABLE | CREATE TABLE                                                                                                                                                                                                                                                                                   |

+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| emp   | CREATE TABLE `emp` (

       `id` bigint(11) NOT NULL AUTO_INCREMENT,

       `name` varchar(255) DEFAULT NULL,

       `dept_no` int(11) DEFAULT NULL,

       `salary` bigint(10) DEFAULT NULL,

       PRIMARY KEY (`id`)

) ENGINE = InnoDB AUTO_INCREMENT = 100005 DEFAULT CHARSET = utf8

PARTITION BY KEY(`id`)

PARTITIONS 2 |

+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 row in set (0.01 sec)

2 测试表已有数据


MySQL [test]> select count(*) from emp;

+----------+

| count(*) |

+----------+

|     1066 |

+----------+

1 row in set (0.05 sec)

MySQL [test]> select * from emp limit 5;

+------+----------------------+---------+--------+

| id   | name                 | dept_no | salary |

+------+----------------------+---------+--------+

|    6 |  Marlena  Normanvell |      27 |     55 |

|    2 |  Bobina  De-Ville    |       5 |     35 |

|    8 |  Murielle Crosser    |       3 |     97 |

|    4 |  Danyette  Debold    |       4 |     30 |

|   10 |  Crosby  Ather       |      27 |      7 |

+------+----------------------+---------+--------+

5 rows in set (0.29 sec)

MySQL [test]> select count(*) from dept;

+----------+

| count(*) |

+----------+

|       15 |

+----------+

1 row in set (0.07 sec)

MySQL [test]> select * from dept limit 5;

+---------+-----------+-----------+

| dept_no | dept_name | loc       |

+---------+-----------+-----------+

|       1 | 广告部    | 襄阳市    |

|       5 | 研发部    | 黑河市    |

|       8 | 研发部    | 本溪市    |

|       9 | 总务部    | 温州市    |

|      10 | 广告部    | 长春市    |

+---------+-----------+-----------+

5 rows in set (0.10 sec)


3 dept表为非广播表时的执行计划

explain select a.name,a.salary, b.dept_name from emp a inner join  dept b on a.dept_no=b.dept_no where b.dept_no=9;

MySQL [test]> explain select a.name,a.salary, b.dept_name from emp a inner join  dept b on a.dept_no=b.dept_no where b.dept_no=9;

   +---------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | LOGICAL EXECUTIONPLAN                                                                                                                                               |

   +---------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | Project(name="name", salary="salary", dept_name="dept_name")                                                                                                        |

   |   BKAJoin(condition="dept_no = dept_no", type="inner")                                                                                                              |

   |     LogicalView(tables="dept[p11]", sql="SELECT `dept_no`, `dept_name` FROM `dept` AS `dept` WHERE (`dept_no` = ?)")                                                |

   |     Gather(concurrent=true)                                                                                                                                         |

   |       LogicalView(tables="emp[p1,p2]", shardCount=2, sql="SELECT `name`, `dept_no`, `salary` FROM `emp` AS `emp` WHERE ((`dept_no` = ?) AND (`dept_no` IN (...)))") |

   | HitCache:true                                                                                                                                                       |

   | Source:PLAN_CACHE                                                                                                                                                   |

   | TemplateId: 73dc4e54                                                                                                                                                |

   +---------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   8 rows in set (0.03 sec)

这个join的表中,dept的数据只有30行,where条件为dept中列,集群在选择执行计划时,没有将join下推到存储节点,而是从存储节点拉取数据,在计算节点进行join。

4 dept为广播表时的执行计划

--将dept表创建为广播表,再看测试计划

MySQL [test]> show create table dept_b;

   +--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | TABLE  | CREATE TABLE                                                                                                                                                                                                |

   +--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | dept_b | CREATE TABLE `dept_b` (

           `dept_no` tinyint(4) NOT NULL,

           `dept_name` varchar(20) DEFAULT NULL,

           `loc` varchar(30) DEFAULT NULL,

           PRIMARY KEY (`dept_no`)

   ) ENGINE = InnoDB DEFAULT CHARSET = utf8

   BROADCAST |

   +--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   1 row in set (0.03 sec)

MySQL [test]> insert into dept_b select * from dept;

   Query OK, 15 rows affected (0.54 sec)

--执行计划中将join操作下推到了每个存储节点

MySQL [test]> explain select a.name,a.salary, b.dept_name from emp a inner join  dept_b b on a.dept_no=b.dept_no where b.dept_no=9;

   +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | LOGICAL EXECUTIONPLAN                                                                                                                                                                                                                                                             |

   +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | Gather(concurrent=true)                                                                                                                                                                                                                                                           |

   |   LogicalView(tables="emp[p1,p2],dept_b", shardCount=2, sql="SELECT `emp`.`name`, `emp`.`salary`, `dept_b`.`dept_name` FROM `emp` AS `emp` INNER JOIN `dept_b` AS `dept_b` ON (((`dept_b`.`dept_no` = ?) AND (`emp`.`dept_no` = `dept_b`.`dept_no`)) AND (`emp`.`dept_no` = ?))") |

   | HitCache:false                                                                                                                                                                                                                                                                    |

   | Source:PLAN_CACHE                                                                                                                                                                                                                                                                 |

   | TemplateId: 3ecd1ad1                                                                                                                                                                                                                                                              |

   +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   5 rows in set (0.22 sec)

--以a表中的数据作为查询条件做点差

MySQL [test]> explain select a.name,a.salary, b.dept_name from emp a inner join  dept_b b on a.dept_no=b.dept_no where a.id=2;

   +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | LOGICAL EXECUTIONPLAN                                                                                                                                                                                                        |

   +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   | Gather(concurrent=true)                                                                                                                                                                                                      |

   |   LogicalView(tables="emp[p1],dept_b", sql="SELECT `emp`.`name`, `emp`.`salary`, `dept_b`.`dept_name` FROM `emp` AS `emp` INNER JOIN `dept_b` AS `dept_b` ON ((`emp`.`dept_no` = `dept_b`.`dept_no`) AND (`emp`.`id` = ?))") |

   | HitCache:true                                                                                                                                                                                                                |

   | Source:PLAN_CACHE                                                                                                                                                                                                            |

   | TemplateId: d78a561e                                                                                                                                                                                                         |

   +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

   5 rows in set (0.01 sec)

MySQL [test]> explain select a.name,a.salary, b.dept_name from emp a inner join  dept b on a.dept_no=b.dept_no where a.id=2;

   +--------------------------------------------------------------------------------------------------------------------------------------------------------+

   | LOGICAL EXECUTIONPLAN                                                                                                                                  |

   +--------------------------------------------------------------------------------------------------------------------------------------------------------+

   | Project(name="name", salary="salary", dept_name="dept_name")                                                                                           |

   |   BKAJoin(condition="dept_no = dept_no", type="inner")                                                                                                 |

   |     LogicalView(tables="emp[p1]", sql="SELECT `name`, `dept_no`, `salary` FROM `emp` AS `emp` WHERE (`id` = ?)")                                       |

   |     Gather(concurrent=true)                                                                                                                            |

   |       LogicalView(tables="dept[p1,p2,p3,...p16]", shardCount=16, sql="SELECT `dept_no`, `dept_name` FROM `dept` AS `dept` WHERE (`dept_no` IN (...))") |

   | HitCache:false                                                                                                                                         |

   | Source:PLAN_CACHE                                                                                                                                      |

   | TemplateId: 1253bcbb                                                                                                                                   |

   +--------------------------------------------------------------------------------------------------------------------------------------------------------+

   8 rows in set (0.07 sec)


在使用广播表时,计算节点直接将join推到了响应的存储节点执行,而在使用单表时,dept作为外表,需要在所有节点上执行,最后在计算节点做join,消耗的资源要远大于使用广播表时。

4 结论

 当大表与小表做join时,将小表设置为广播表,在以大表的分区列做查询时可以大幅度提高查询性能。当以小表的分区列也可以join下推到存储节点执行,从而节省计算节点的存储资源。

相关实践学习
快速体验PolarDB开源数据库
本实验环境已内置PostgreSQL数据库以及PolarDB开源数据库:PolarDB PostgreSQL版和PolarDB分布式版,支持一键拉起使用,方便各位开发者学习使用。
相关文章
|
5月前
|
数据库 SQL Cloud Native
DBA福利:云原生分布式数据库 PolarDB-X 操作指南
【6月更文挑战第2天】简述如何使用PXD工具一键安装PolarDB-X操作
72055 10
|
6月前
|
存储 关系型数据库 MySQL
PolarDB-X 存储引擎核心技术 | 索引回表优化
数据库系统为了高效地存储、检索和维护数据,采用了多种不同的数据组织结构。不同的组织结构有其特定的用途和优化点,比如提高查询速度、优化写入性能、减少存储空间等,目前 PolarDB-X 采用了 B-Tree 的索引组织结构。
|
6月前
|
监控 关系型数据库 分布式数据库
【PolarDB 开源】PolarDB HTAP 实践:混合事务与分析处理的性能优化策略
【5月更文挑战第21天】PolarDB开源后在HTAP领域表现出色,允许在同一系统处理事务和分析工作负载,提高数据实时性。通过资源分配、数据分区、索引优化等策略提升性能。示例代码展示了创建和查询事务及分析表的基本操作。PolarDB还提供监控工具,帮助企业优化系统并应对业务变化。其HTAP能力为开发者和企业提供了强大支持,推动技术进步,加速数字化时代的业务发展。
435 1
|
3月前
|
存储 缓存 负载均衡
【PolarDB-X 技术揭秘】Lizard B+tree:揭秘分布式数据库索引优化的终极奥秘!
【8月更文挑战第25天】PolarDB-X是阿里云的一款分布式数据库产品,其核心组件Lizard B+tree针对分布式环境优化,解决了传统B+tree面临的数据分片与跨节点查询等问题。Lizard B+tree通过一致性哈希实现数据分片,确保分布式一致性;智能分区实现了负载均衡;高效的搜索算法与缓存机制降低了查询延迟;副本机制确保了系统的高可用性。此外,PolarDB-X通过自适应分支因子、缓存优化、异步写入、数据压缩和智能分片等策略进一步提升了Lizard B+tree的性能,使其能够在分布式环境下提供高性能的索引服务。这些优化不仅提高了查询速度,还确保了系统的稳定性和可靠性。
90 5
|
3月前
|
存储 Oracle 关系型数据库
PolarDB-X 存储引擎核心技术 | Lizard B+tree 优化
PolarDB-X 分布式数据库,采用集中式和分布式一体化的架构,为了能够灵活应对混合负载业务,作为数据存储的 Data Node 节点采用了多种数据结构,其中使用行存的结构来提供在线事务处理能力,作为 100% 兼容 MySQL 生态的数据库,DN 在 InnoDB 的存储结构基础上,进行了深度优化,大幅提高了数据访问的效率。
7454 13
|
3月前
|
存储 算法 Cloud Native
【PolarDB-X列存魔法】揭秘TPC-H测试背后的性能优化秘籍!
【8月更文挑战第25天】阿里巴巴的云原生数据库PolarDB-X以其出色的性能、可靠性和扩展性闻名,在多种业务场景中广泛应用。尤其在列存储模式下,PolarDB-X针对分析型查询进行了优化,显著提升了数据读取效率。本文通过TPC-H基准测试探讨PolarDB-X列存执行计划的优化策略,包括高效数据扫描、专用查询算法以及动态调整执行计划等功能,以满足复杂查询的需求并提高数据分析性能。
92 1
|
3月前
|
关系型数据库 MySQL 分布式数据库
PolarDB 并行查询问题之处理类似JOIN和GROUP BY的复杂查询如何解决
PolarDB 并行查询问题之处理类似JOIN和GROUP BY的复杂查询如何解决
23 1
|
3月前
|
C# UED 定位技术
WPF控件大全:初学者必读,掌握控件使用技巧,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,控件是实现用户界面交互的关键元素。WPF提供了丰富的控件库,包括基础控件(如`Button`、`TextBox`)、布局控件(如`StackPanel`、`Grid`)、数据绑定控件(如`ListBox`、`DataGrid`)等。本文将介绍这些控件的基本分类及使用技巧,并通过示例代码展示如何在项目中应用。合理选择控件并利用布局控件和数据绑定功能,可以提升用户体验和程序性能。
65 0
|
4月前
|
分布式计算 DataWorks 关系型数据库
DataWorks产品使用合集之同样的表和数据,在PolarDB执行LEFT JOIN查询可以得到结果,但在MaxCompute中却返回为空,是什么原因
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
4月前
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用问题之Join评估的行数比索引的基数小,是什么导致的
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。

热门文章

最新文章