第7.1章:StarRocks性能调优——查询分析

目录

一、查看查询计划

1.1 概述

1.2 查询计划树

1.3 查看查询计划的命令

1.3 查看查询计划

二、查看查询Profile 

2.1 启用 Query Profile

2.2 获取 Query Profile

2.3 Query Profile结构与详细指标 

2.3.1 Query Profile的结构

2.3.2 Query Profile的合并策略

2.3.3 Query Profile的详细指标 

三、Query Hint

3.1 概述

3.2 系统变量 Hint

3.3 Join Hint

    为了优化StarRocks集群性能,需要定期对慢查询进行分析优化,避免慢查询影响整个集群的服务能力。query plan查询计划是FE通过解析sql生成的执行计划,而profile是BE执行查询后的结果,包含了每一步的耗时和数据处理量等数据。

一、查看查询计划

1.1 概述

   在StarRocks中,一条sql语句的生命周期可以分为(简化版)为查询解析(query parsing)查询计划(query plan)、执行(query execution)三个阶段。一般而言,查询解析不会成为查询性能的瓶颈,因为分析型需求的qps(“每秒查询率”或“每秒请求数”)不高。所以决定查询性能的关键就在于查询规划(query plan)和查询执行(query execution)。两者关系是:query plan负责组织算子(scan/join/aggregation)之间的关系,query execution负责执行具体算子。

1.2 查询计划树

    查询规划器用来决定数据库如何具体执行一个 SQL 的,比如用户指定了一个 Join 算子,则查询规划器需要决定具体的 Join 算法,比如是使用 Shuffle 还是 Broadcast;Join顺序是否需要调整以避免笛卡尔积;以及确定最终的在哪些节点执行等等。

  Doris的查询规划器是先将一个 SQL语句转换成一个单机执行计划树,SQL --> PlanNodeTree

    之后,查询规划器会根据具体的算子执行方式、数据的具体分布,将单机查询计划转换为分布式查询计划,即PlanNodeTree --->PlanFragmentTree,分布式查询计划是由多个Plan Fragment 组成的,例如:Plan Fragment 0,Plan Fragment 1,Plan Fragment 2deng 。每个 Fragment 负责查询计划的一部分,各个Fragment之间会通过DataStreamSink和ExchangeNode 算子进行数据的传输。

   

   如上图,我们将单机计划分成了两个 Fragment:F1 和 F2。两个 Fragment 之间通过一个 ExchangeNode 节点传输数据。而一个Fragment 会进一步的划分为多个Instance。Instance 是最终具体的执行实例。划分成多个 Instance 有助于充分利用机器资源,提升一个 Fragment 的执行并发度

1.3 查看查询计划的命令

   query plan可以分为逻辑执行计划(logical query plan)和物理执行计划(physical query plan),本文说的query plan默认指代的都是逻辑执行计划。 通过explain  sql_statement 命令查看query plan。

   ps: Doris中的命令更丰富:查询分析 - Apache Doris

1.3 查看查询计划

    来自StarRocks官网案例:分析查询 | StarRocks

     查询计划涉及的概念: 

 以下面这个query plan查询计划为例,进行分析:

mysql> EXPLAIN select count(*)
from store_sales, household_demographics, time_dim, store
where ss_sold_time_sk = time_dim.t_time_skand ss_hdemo_sk = household_demographics.hd_demo_skand ss_store_sk = s_store_skand time_dim.t_hour = 8and time_dim.t_minute >= 30and household_demographics.hd_dep_count = 5and store.s_store_name = 'ese'
order by count(*) limit 100;+------------------------------------------------------------------------------+
| Explain String                                                               |
+------------------------------------------------------------------------------+
| PLAN FRAGMENT 0                                                              |
|  OUTPUT EXPRS:<slot 11>                                                      |
|   PARTITION: UNPARTITIONED                                                   |
|   RESULT SINK                                                                |
|   12:MERGING-EXCHANGE                                                        |
|      limit: 100                                                              |
|      tuple ids: 5                                                            |
|                                                                              |
| PLAN FRAGMENT 1                                                              |
|  OUTPUT EXPRS:                                                               |
|   PARTITION: RANDOM                                                          |
|   STREAM DATA SINK                                                           |
|     EXCHANGE ID: 12                                                          |
|     UNPARTITIONED                                                            |
|                                                                              |
|   8:TOP-N                                                                    |
|   |  order by: <slot 11> ASC                                                 |
|   |  offset: 0                                                               |
|   |  limit: 100                                                              |
|   |  tuple ids: 5                                                            |
|   |                                                                          |
|   7:AGGREGATE (update finalize)                                              |
|   |  output: count(*)                                                        |
|   |  group by:                                                               |
|   |  tuple ids: 4                                                            |
|   |                                                                          |
|   6:HASH JOIN                                                                |
|   |  join op: INNER JOIN (BROADCAST)                                         |
|   |  hash predicates:                                                        |
|   |  colocate: false, reason: left hash join node can not do colocate        |
|   |  equal join conjunct: `ss_store_sk` = `s_store_sk`                       |
|   |  tuple ids: 0 2 1 3                                                      |
|   |                                                                          |
|   |----11:EXCHANGE                                                           |
|   |       tuple ids: 3                                                       |
|   |                                                                          |
|   4:HASH JOIN                                                                |
|   |  join op: INNER JOIN (BROADCAST)                                         |
|   |  hash predicates:                                                        |
|   |  colocate: false, reason: left hash join node can not do colocate        |
|   |  equal join conjunct: `ss_hdemo_sk`=`household_demographics`.`hd_demo_sk`|
|   |  tuple ids: 0 2 1                                                        |
|   |                                                                          |
|   |----10:EXCHANGE                                                           |
|   |       tuple ids: 1                                                       |
|   |                                                                          |
|   2:HASH JOIN                                                                |
|   |  join op: INNER JOIN (BROADCAST)                                         |
|   |  hash predicates:                                                        |
|   |  colocate: false, reason: table not in same group                        |
|   |  equal join conjunct: `ss_sold_time_sk` = `time_dim`.`t_time_sk`         |
|   |  tuple ids: 0 2                                                          |
|   |                                                                          |
|   |----9:EXCHANGE                                                            |
|   |       tuple ids: 2                                                       |
|   |                                                                          |
|   0:OlapScanNode                                                             |
|      TABLE: store_sales                                                      |
|      PREAGGREGATION: OFF. Reason: `ss_sold_time_sk` is value column          |
|      partitions=1/1                                                          |
|      rollup: store_sales                                                     |
|      tabletRatio=0/0                                                         |
|      tabletList=                                                             |
|      cardinality=-1                                                          |
|      avgRowSize=0.0                                                          |
|      numNodes=0                                                              |
|      tuple ids: 0                                                            |
|                                                                              |
| PLAN FRAGMENT 2                                                              |
|  OUTPUT EXPRS:                                                               |
|   PARTITION: RANDOM                                                          |
|                                                                              |
|   STREAM DATA SINK                                                           |
|     EXCHANGE ID: 11                                                          |
|     UNPARTITIONED                                                            |
|                                                                              |
|   5:OlapScanNode                                                             |
|      TABLE: store                                                            |
|      PREAGGREGATION: OFF. Reason: null                                       |
|      PREDICATES: `store`.`s_store_name` = 'ese'                              |
|      partitions=1/1                                                          |
|      rollup: store                                                           |
|      tabletRatio=0/0                                                         |
|      tabletList=                                                             |
|      cardinality=-1                                                          |
|      avgRowSize=0.0                                                          |
|      numNodes=0                                                              |
|      tuple ids: 3                                                            |
|                                                                              |
| PLAN FRAGMENT 3                                                              |
|  OUTPUT EXPRS:                                                               |
|   PARTITION: RANDOM                                                          |
|   STREAM DATA SINK                                                           |
|     EXCHANGE ID: 10                                                          |
|     UNPARTITIONED                                                            |
|                                                                              |
|   3:OlapScanNode                                                             |
|      TABLE: household_demographics                                           |
|      PREAGGREGATION: OFF. Reason: null                                       |
|      PREDICATES: `household_demographics`.`hd_dep_count` = 5                 |
|      partitions=1/1                                                          |
|      rollup: household_demographics                                          |
|      tabletRatio=0/0                                                         |
|      tabletList=                                                             |
|      cardinality=-1                                                          |
|      avgRowSize=0.0                                                          |
|      numNodes=0                                                              |
|      tuple ids: 1                                                            |
|                                                                              |
| PLAN FRAGMENT 4                                                              |
|  OUTPUT EXPRS:                                                               |
|   PARTITION: RANDOM                                                          |
|   STREAM DATA SINK                                                           |
|     EXCHANGE ID: 09                                                          |
|     UNPARTITIONED                                                            |
|                                                                              |
|   1:OlapScanNode                                                             |
|      TABLE: time_dim                                                         |
|      PREAGGREGATION: OFF. Reason: null                                       |
|      PREDICATES: `time_dim`.`t_hour` = 8, `time_dim`.`t_minute` >= 30        |
|      partitions=1/1                                                          |
|      rollup: time_dim                                                        |
|      tabletRatio=0/0                                                         |
|      tabletList=                                                             |
|      cardinality=-1                                                          |
|      avgRowSize=0.0                                                          |
|      numNodes=0                                                              |
|      tuple ids: 2                                                            |
+------------------------------------------------------------------------------+
128 rows in set (0.02 sec)

  解析过程:query plan分为 5 个pan fragment,编号从 0 至4,通过从下至上的方式查看query plan。

    step1:最底部的 Plan Fragment 为 Fragment 4,它负责扫描time_dim表,并提前执行相关查询条件 time_dim.t_hour = 8 and time_dim.t_minute >= 30,即谓词下推。这里的time_dim表采用的是聚合表,对于聚合表(Aggregate Key),StarRocks 会根据不同查询选择是否开启预聚合 PREAGGREGATION。以上示例中 time_dim 表的预聚合为关闭状态,此状态之下 StarRocks 会读取 time_dim 的全部维度列,如果当前表包含大量维度列,这可能会成为影响性能的一个关键因素。如果 time_dim 表被设置为根据 Range Partition 进行数据划分(数据分区),Query Plan 中的 partitions 会表征查询命中的分区,无关分区被自动过滤,从而有效减少扫描数据量。如果当前表有物化视图,StarRocks 会根据查询去自动选择物化视图,如果没有物化视图,那么查询自动命中 base table(基表),也就是以上示例中展示的 rollup: time_dim

  step2:当 time_dim 表数据扫描完成之后,Fragment 4 的执行过程也就随之结束,此时它将扫描得到的数据传递给其他 Fragment(各个Fragment之间,通过DataStreamSink和ExchangeNode 算子进行数据的传输。以上示例 EXCHANGE ID : 09 表征了数据传递给了标号为 9 的接收节点。

   Fragment 2,3,4功能类似,只是负责扫描的表不同。而查询中的 Order/Aggregation/Join 算子,都在 Fragment 1 中进行。

  step3:Fragment 1 集成了三个 Join 算子的执行,采用默认的 BROADCAST 方式进行执行,也就是小表向大表广播的方式进行。如果两个 Join 的表都是大表,建议采用 SHUFFLE 的方式进行。目前 StarRocks 只支持 HASH JOIN,也就是采用哈希算法进行 Join。以上示例中的 colocate 字段用来表述两张 Join 表采用同样的分区/分桶方式。如果分区/分桶方式相同,Colocate Join 的过程可以直接在本地执行,不用进行数据的移动。Join 执行完成之后,Fragment 1 就会执行上层的 Aggregation、Order by 和 TOP-N 算子。

二、查看查询Profile 

2.1 启用 Query Profile

   官网文章地址:Query Profile 概述 | StarRocks

    Profile 包含了一个sql查询涉及的所有工作节点的执行信息,有助于我们分析查询性能的瓶颈。将变量 enable_profile 设置为 true 以启用 Query Profile:SET enable_profile = true;

2.2 获取 Query Profile

以下步骤获取 Query Profile:

  1. 在浏览器中访问 http://<fe_ip>:<fe_http_port>
  2. 在显示的页面上,单击顶部导航中的 queries
  3. 在 Finished Queries 列表中,选择您要分析的查询并单击 Profile 列中的链接。

   页面将跳转至相应 Query Profile

2.3 Query Profile结构与详细指标 

2.3.1 Query Profile的结构

   Query Profile 的结构与执行引擎的设计密切相关,由以下五部分组成:

  • Fragment:执行树。一个查询由一个或多个Fragment组成
  • FragmentInstance:每个Fragment可以有多个实例,每个实例称作FragmentInstance,分别由不同的计算节点来执行
  • Pipeline:一个FragmentInstance会被拆分成多个Pipeline,每个Pipeline是一个执行链,由一组首尾相接的 Operator 构成。
  • PipelineDriver:一个 Pipeline 可以有多个实例,每个实例称为 PipelineDriver,以充分利用多个计算核心。
  • Operator:算子,一个 PipelineDriver 由多个 Operator 组成。

2.3.2 Query Profile的合并策略

    同一个Fragment 关联的多个 FragmentInstance 在结构上具有高度相似性。为了减少 Query Profile 的体积,可以将 FragmentInstance 层进行合并,原本的五层结构便简化为三层:

  • Fragment:执行树
  • Pipeline:执行链
  • Operator:算子

 通过一个 Session变量 pipeline_profile_level 来控制这个合并行为,其可选值有2个:

  • 1:合并,即三层结构。默认值。
  • 2:不合并,即保留原始的五层结构。
  • 其他任何数值都会被当成默认值 1

 通常没有必要调整这个参数,就采取默认值1

2.3.3 Query Profile的详细指标 

 太多了,看官网:Query Profile 结构与详细指标 | StarRocks

三、Query Hint

3.1 概述

   Hint是一种指令或注释,显式地向查询优化器建议如何执行查询,Hint 仅在单个查询范围内生效。 StarRocks 目前支持两种 Hint:系统变量 Hint 和 Join Hint

3.2 系统变量 Hint

    在 selec等语句中通过 /*+ ... */ 注释的形式设置一个或多个系统变量 hint。其他语句中如果包含 select 子句(如创建物化视图create materialized view as select,创建视图create view as select),则也可以在该 select 子句中使用系统变量 hint。

 select [/*+ set_var(key=value [, key = value]*) */] ...
#创建物化视图时在 SELECT 子句中通过系统变量 query_timeout 来设置查询执行超时时间。
create materialized view mv 
partition by dt 
distributed by hash(`key`) 
buckets 10 
refresh async 
as select /*+ set_var(query_timeout=500) */ * from dual;

3.3 Join Hint

    针对多表关联查询,优化器一般会主动选择最优的 Join 执行方式(Join Reorder)。在特殊情况下,用户使用 Join Hint显式地指定Join 执行方式。目前 Join Hint 支持的Join执行方式有Broadcast Join、Shuffle Join、Bucket Shuffle Join 和 Colocate Join。

  当Join Hint指定Colocate Join或 Bucket Shuffle Join 时,需要确保表的数据分布情况满足这两种 Join 执行方式的要求,否则用户指定的Join执行方式不生效。

#语法
... join { [broadcast] | [shuffle] | [bucket] | [colocate] | [unreorder]} ...#说明:使用 Join Hint 时大小写不敏感。

举例:

  • Shuffle Join

     如果需要将表 A、B 中分桶键取值相同的数据行 Shuffle 到相同机器上,再进行 Join 操作,您可以设置 Join Hint 为 Shuffle Join。

select k1 from t1 join [SHUFFLE] t2 on t1.k1 = t2.k2 group by t2.k2;
  • Broadcast Join

   如果表 A 是个大表,表 B 是个小表,则可以设置 Join Hint 为 Broadcast Join。表 B 的数据全量广播到表 A 数据所在的机器上,再进行 Join 操作。Broadcast Join 相比较于 Shuffle Join,节省了 Shuffle 表 A 数据的开销。

select k1 from t1 join [broadcast] t2 on t1.k1 = t2.k2 group by t2.k2;
  • Bucket Shuffle Join

    如果关联查询中 Join 命中表 A 的分桶键 ,且表 A 和表 B 均是大表的情况下,可以设置 Join Hint 为 Bucket Shuffle Join。表 B 数据会按照表 A 数据的分布方式,Shuffle 到表 A 数据所在机器上,再进行 Join 操作。Bucket Shuffle Join 是在 Broadcast Join 的基础上进一步优化,Shuffle B 表的数据量全局只有一份,比 Broadcast Join 少传输了很多倍数据量。

select k1 from t1 join [bucket] t2 on t1.k1 = t2.k2 group by t2.k2;
  • Colocate Join

    如果建表时指定表A 和 B属于同一个 Colocation Group,则表 A 和表 B 分桶键取值相同的数据行一定分布在相同 BE 节点上。当关联查询中 Join命中表 A 和 B 的分桶键,可以设置 Join Hint 为 Colocate Join。 具有相同键值的数据直接在本地 Join,减少数据在节点间的传输耗时,从而提高查询性能。

select k1 from t1 join [colocate] t2 on t1.k1 = t2.k2 group by t2.k2;

  通过explain命令来查看 Join Hint 是否生效。如果返回结果所显示的 Join 执行方式符合 Join Hint,则表示 Join Hint 生效。

explain select k1 from t1 join [colocate] t2 on t1.k1 = t2.k2 group by t2.k2;

参考文章:

StarRocks技术内幕:查询原理浅析

【源码解析系列】 Apache Doris 查询源码解析

Doris的查询计划-腾讯云开发者社区-腾讯云

分析查询 | StarRocks

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2809869.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

汇总利用YOLO8训练遇到的报错和解决方案(包含训练过程中验证阶段报错、精度报错、损失为Nan、不打印GFLOPs)

一、本文介绍 本文为专栏内读者和我个人在训练YOLOv8时遇到的各种错误解决方案,你遇到的问题本文基本上都能够解决,同时本文的内容为持续更新,定期汇总大家遇到的问题已经一些常见的问题答案,目前包含的问题已经解决方法汇总如下图所示。 专栏目录:YOLOv8改进有效系列目录…

机器人内部传感器阅读笔记及心得-位置传感器-旋转变压器、激光干涉式编码器

旋转变压器 旋转变压器是一种输出电压随转角变化的检测装置&#xff0c;是用来检测角位移的&#xff0c;其基本结构与交流绕线式异步电动机相似&#xff0c;由定子和转子组成。 旋转变压器的原理如图1所示&#xff0c;定子相当于变压器的一次侧&#xff0c;有两组在空间位置上…

Python及Pycharm专业版下载安装教程(Python 3.11版)附JetBrains学生认证教程

目录 一、Python下载及安装1、Python下载2、Python安装3、验证是否安装成功 二、PyCharm下载及安装1、PyCharm下载2、PyCharm安装3、激活PyCharm 三、JetBrains学生认证 本篇主要介绍Python和PyCharm专业版的下载及安装方式&#xff0c;以及通过两种方式进行JetBrains学生认证。…

CAS5.3使用JPA实现动态注册服务

cas同时支持cas协议和OAuth2协议,官方默认是通过扫描json文件的形式注册客户端服务,但是此种方式需要重启服务才能生效,此次我们将使用JPA来完美实现动态注册服务,如果不知道cas如何部署,可以擦看之前的文章 cas-client基于CAS协议客户端搭建-CSDN博客 cas-server5.3自定义密…

家用超声波清洗机哪个好?四款高评分超声波清洗机分享

超声波清洗机可以说是眼镜党家中必备的一款超声波清洗机&#xff0c;毕竟它能高效的帮我们解决清洗眼镜的烦恼&#xff0c;也可以帮我们清洗家中其他的一些物品。很多朋友因为各种原因没有时间清洗眼镜以及家中的小物件物品&#xff0c;长时间下来一次物品或者是眼镜上就会堆积…

构建高效稳定的外卖平台架构设计与实现

外卖行业的快速发展为人们的生活带来了便利&#xff0c;随着外卖市场的扩大和竞争的加剧&#xff0c;外卖平台的架构设计变得至关重要。一个高效稳定的架构可以支持平台的快速发展&#xff0c;提供优质的服务体验&#xff0c;同时保障用户数据的安全性。 用户端架构设计 移动端…

【C#】获取文本中的链接,通过正则表达式的方法获取以及优化兼容多种格式

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…

淘宝京东1688实时API商品详情数据解析:获取市场最新趋势

实时API商品详情数据解析&#xff1a;获取市场最新趋势 在快速变化的商业环境中&#xff0c;实时数据成为企业把握市场动态和竞争优势的关键。特别是对于电商行业而言&#xff0c;实时API商品详情数据成为了获取市场最新趋势的重要工具。本文将深入探讨如何通过实时API商品详情…

HTTPS对HTTP的加密过程

1、HTTPS是在HTTP的基础上&#xff0c;引入了一个加密层&#xff08;SSL&#xff09;&#xff0c;对数据进行保护&#xff0c;HTTP 是明文传输的&#xff08;不安全&#xff0c;很可能会被运营商通过referer劫持&#xff0c;或者黑客通过修改链接来窃数据&#xff09; 2、加密…

计网:动手尝试SMTP交互【利用Telnet发送邮件, 带图片】

文章目录 准备工作发送仅有ascii码的邮件发送图片附件后记 准备工作 1.如图&#xff0c;勾选telnet客户端 2.邮箱开启第三方登录服务 开启服务后&#xff0c;会给一个授权码。授权码是QQ邮箱用于登录第三方客户端/服务的专用密码&#xff0c;适用于登录以下服务&#xff1a;…

自定义el-upload 上传文件

前言 最近在做一个文件上传的功能&#xff0c;后端接口写好了、发现前端上传文件的页面不会写……&#xff08;我很笨的&#xff09;然后我就找啊找发现element有个组件是<el-upload/>能直接上传文件。我就想直接用拿来改改改成自己想要的&#xff0c;可是就是这样我花了…

银河麒麟操作系统安装Anaconda

下载 首先确认需要安装的版本 uname -maarch64https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?CM&OD 在上面网址中下载相应的版本 下载后&#xff0c;上传到服务器 安装 bash Anaconda3-2023.09-0-Linux-aarch64.sh 点击enter&#xff0c;继续 输入yes同意许…

MongoDB之客户端工具与核心概念及基本类型篇

MongoDB之客户端工具与核心概念及基本类型篇 文章目录 MongoDB之客户端工具与核心概念及基本类型篇1. MongoDB是什么?1. 关于MongoDB2. 相关客户端工具1. MongoDB Compass2. Studio 3T3. Navicat for MongoDB4. NoSQL Manager for MongoDB Professional 2.MongoDB相关概念2.1 …

苹果 CMS 大橙子 vfed 5.0优化版

大橙子模版算是在苹果 CMS 众多主题里&#xff0c;较为亮眼的一款了&#xff0c;主题简洁&#xff0c;功能众多&#xff0c;非常的齐全。 今天分享的就是大橙 5.0 版本模板&#xff0c;完美破解&#xff0c;自测无后门&#xff0c;无广告不影响任何功能体验性。下载地址&#…

恒峰-高压森林应急消防泵:守护绿色生命线

随着城市化进程的加快&#xff0c;森林覆盖率逐渐降低&#xff0c;人们对于森林资源的保护意识也在不断提高。然而&#xff0c;一旦发生森林火灾&#xff0c;将会给生态环境带来极大的破坏。因此&#xff0c;如何提高森林火灾的防治能力&#xff0c;成为了亟待解决的问题。而高…

Spring Boot Profiles简单介绍

Spring Boot application.properties和application.yml文件的配置 阅读本文之前&#xff0c;请先阅读上面的配置文件介绍。 Spring Boot Profiles是一个用于区分不同环境下配置的强大功能。以下是如何在Spring Boot应用程序中使用Profiles的详细步骤和代码示例。 1. 创…

HarmonyOS4.0系统性深入开发36 媒体查询(mediaquery)

媒体查询&#xff08;mediaquery&#xff09; 概述 媒体查询作为响应式设计的核心&#xff0c;在移动设备上应用十分广泛。媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。媒体查询常用于下面两种场景&#xff1a; 针对设备和应用的属性信息&#xff08;比如显…

密码学及其应用(应用篇15)——0/1背包问题

1 问题背景 背包问题是一个经典的优化问题&#xff0c;在计算机科学和运筹学中有着广泛的应用。具体到你提到的这个问题&#xff0c;它是背包问题中的一个特例&#xff0c;通常被称为0/1背包问题。这里&#xff0c;我们有一系列的正整数 &#xff0c;以及一个正整数&#xff0c…

opengles 绘制图元 ——glDrawArrays() 相关API介绍 (十)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、opengles3.0 绘制图元介绍二、绘图图元 API 介绍1. glDrawArrays()1.1 glDrawArrays()函数原型1.2 GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN 三者的区别1.3 使用GL_TRIANGLES, G…

java-map集合的基本使用

一、HashMap集合 1.HashMap示意图 2.HashMap的特点 3.HashMap的常用方法 ①.put(K key, V value) 将键&#xff08;key&#xff09;/值&#xff08;value&#xff09;映射存放到Map集合中 public class Test {public static void main(String[] args) {HashMap<String, I…