Hive执行计划之hive依赖及权限查询和常见使用场景

news2024/11/27 19:47:49

文章目录

    • 概述
    • 1.explain dependency的查询与使用
    • 2.借助explain dependency解决一些常见问题
      • 2.1.识别看似等价的SQL代码实际上是不等价的:
      • 2.2 通过explain dependency验证将过滤条件在不同位置的查询区别
    • 3.查看SQL操作涉及到的相关权限信息

概述

Hive查看执行计划的命令中还有两个不怎么常用但很重要的命令,接下来详细介绍一下。

有一个问题:如何在hiveSQL执行之前就探查到这段逻辑的血缘依赖关系?

hive血缘是很多生产级数仓必须要提供的功能,大多数解决方案都是使用hive hooks的方法通过SQL执行后解析得到hive表的依赖关系

这个方案能细粒度到字段级依赖,属于很完善的一个解决方案,但有很多场景我们需要在SQL执行之前就得到依赖关系,那么如何解决的呢?

1.explain dependency的查询与使用

explain dependency 提供了这样的一个解决方案,它可以查询一段SQL需要的数据来源,以JSON的形式展现结果数据。里面主要包含两部分内容:

  • input_tables:描述一段SQL依赖的数据来源表,里面存储的是hive表名的列表,格式如下:

    {"tablename":"库名@表名","tabletype":"表的类型(外部表/内部表)"}

  • input_partitions:描述一段SQL依赖的数据来源表分区,里面存储的是分区名称的列表,格式如下:

    {"partitionName":"库名@表名@分区列=分区列的值"}

    如果查询的表为非分区表,则显示为空。

可以通过以下例子来进行比对,其中例1是查询非分区普通表SQL的explain dependency,例2是查询分区表SQL的explain dependency。

例1 使用explain dependency查看SQL非分区普通表。

explain dependency
-- 统计年龄小于30岁各个年龄里,昵称里带“小”的人数
select age,count(0) as num from temp.user_info_all_no
where age < 30 and nick like '%小%'
group by age;

输出结果内容:

{"input_tables":[{"tablename":"temp@user_info_all_no","tabletype":"MANAGED_TABLE"}],"input_partitions":[]}

例2 使用explain dependency查看SQL查询分区表。

explain dependency
-- 统计年龄小于30岁各个年龄里,昵称里带“小”的人数,其中ymd字段为分区字段
select age,count(0) as num from temp.user_info_all where ymd >= '20230501'
and age < 30 and nick like '%小%'
group by age;

输出结果内容:

{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230503"},{"partitionName":"temp@user_info_all@ymd=20230504"},{"partitionName":"temp@user_info_all@ymd=20230505"},{"partitionName":"temp@user_info_all@ymd=20230529"}]}

2.借助explain dependency解决一些常见问题

explain dependency的使用场景有以下几个:

场景一,快速排除。快速排除因为读不到相应分区的数据而导致任务数据输出异常。例如,在一个以天为分区的任务中,上游任务因为生产过程不可控因素出现异常或者空跑,导致下游任务引发异常。通过这种方式,可以快速查看SQL读取的分区是否出现异常。

场景二,理清表的输入,帮助理解程序的运行,特别是有助于理解有多重子查询,多表连接的依赖输入。

场景三,提前通过解析hiveSQL脚本进行血缘依赖解析,用于一些定制化数据平台工具开发中的血缘构建。

explain dependency的使用能帮助开发者解决哪些问题呢?

2.1.识别看似等价的SQL代码实际上是不等价的:

对于接触SQL不久的程序员来说,很多人容易将

select * from a left join b on a.no=b.no and a.f>1 and a.f<3;

这段逻辑等价于 select * from a left join b on a.no=b.no where a.f>1 and a.f<3;

这两段的逻辑的区别是在多表left join的时候where 后加条件是否等价与on后面加条件。

我们通过实例来看看其中的区别:

例3 使用explain dependency识别看似等价的SQL代码。

-- 代码1
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd and a.ymd >= '20230501' and a.ymd <= '20230502';

-- 代码2
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd 
where a.ymd >= '20230501' and a.ymd <= '20230502';

输出结果内容:

// 代码1输出结果
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230430"},{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230503"},{"partitionName":"temp@user_info_all@ymd=20230504"},{"partitionName":"temp@user_info_all@ymd=20230505"},{"partitionName":"temp@user_info_all@ymd=20230529"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230503"},{"partitionName":"temp@user_act_info@ymd=20230606"}]}

// 代码2输出结果
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"}]}

通过以上输出结果可以看出,上面例子里的两段SQL其实并不等价。在left join(left outer join)的连接条件中加入非等值的过滤条件后,这里特指作用于a表,也就是连接的基表,并没有将左外连接的左右两个表按照过滤条件进行过滤,左外连接在执行时会读取所有分区数据,然后进行关联数据过滤操作。

left outer join 针对左表非等值条件on和where查询数据on条件查询数据大于where条件查询数据。

下面查看left outer join对右表的过滤条件实例:

例4 使用explain dependency识别left outer join 右表过滤非等值条件区别

-- 代码1
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd and b.ymd >= '20230501' and b.ymd <= '20230502';

-- 代码2
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd 
where b.ymd >= '20230501' and b.ymd <= '20230502';

输出结果内容:

// 代码1输出结果,on后跟非等值条件
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230430"},{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230503"},{"partitionName":"temp@user_info_all@ymd=20230504"},{"partitionName":"temp@user_info_all@ymd=20230505"},{"partitionName":"temp@user_info_all@ymd=20230529"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"}]}

// 代码2输出结果,where后跟非等值条件
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230430"},{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230503"},{"partitionName":"temp@user_info_all@ymd=20230504"},{"partitionName":"temp@user_info_all@ymd=20230505"},{"partitionName":"temp@user_info_all@ymd=20230529"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230503"},{"partitionName":"temp@user_act_info@ymd=20230606"}]}

可以看到left outer join 针对右表非等值条件on和where查询数据左表都是全表扫描,右表on条件是条件过滤,where条件是全表扫描。

接下来对inner join,right outer join,full outer join进行测试。会发现

inner join 的类似针对左右表非等值条件on和where查询数据是等价的。

right outer join和left join相反。

full outer join都是全表扫描。

那么可以很好的判断出一下两段SQL的过滤条件数据读取范围是完全不一样的。就不贴执行结果了。

例5 left outer join下的对左表和右表不等值条件过滤。

-- 代码1
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd and a.ymd >= '20230501' and a.ymd <= '20230502';

-- 代码2
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd and b.ymd >= '20230501' and b.ymd <= '20230502';

以上不同join类型数据查询范围不一致主要原因和hive对join和where的谓词下推支持不同有关。通过explain dependency可以直接验证hive对join和where进行谓词下推规则的验证。
在这里插入图片描述

谓词下推可详细查看什么是谓词下推,看这一篇就够了

2.2 通过explain dependency验证将过滤条件在不同位置的查询区别

如果要使用外连接并需要对左右两个表进行条件过滤,做好的方式是将过滤条件放到就近处,即如果已经知道表数据过滤筛选条件,那么在使用该表前,就先用过滤条件进行过滤,然后进行其他操作。

一些SQL内置优化器会做一些过滤下推优化,但部分条件还是不会进行下推。所以我们在写SQL时尽量养成先过滤而后进行其他操作(聚合,关联)的习惯。

可以看如下实例:

例6 left outer join对左表过滤数据的优化对比。

-- 代码1
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd 
where a.ymd >= '20230501' and a.ymd <= '20230502';

-- 代码2
explain dependency
select a.uid from (
	select uid,ymd from temp.user_info_all
  -- 在子查询内部进行过滤
  where ymd >= '20230501' and ymd <= '20230502'  
) a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd;

-- 代码3
explain dependency
select a.uid from (
	select uid,ymd from temp.user_info_all
  -- 在子查询内部进行过滤
  where ymd >= '20230501' and ymd <= '20230502'  
) a
left outer join (
	select uid,ymd from temp.user_act_info
  where ymd >= '20230501' and ymd <= '20230502'
) b
on a.uid = b.uid and a.ymd = b.ymd;

执行结果:

//代码1,左右表都进行了过滤
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"}]}

//代码2,右表进行了全表扫描
{"input_tables":[{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230503"},{"partitionName":"temp@user_act_info@ymd=20230606"}]}

//代码3,左右表都进行了过滤
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"}]}

可以看到left outer join对左表过滤数据的优化中代码1片段等价于代码3片段,即两表都在就近处都过滤。

例7 left outer join对右表过滤数据的优化对比。

-- 代码1
explain dependency
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd 
where b.ymd >= '20230501' and b.ymd <= '20230502';

-- 代码2
explain dependency
select a.uid from (
	select uid,ymd from temp.user_info_all
  -- 在子查询内部进行过滤
  where ymd >= '20230501' and ymd <= '20230502'  
) a
left outer join (
	select uid,ymd from temp.user_act_info
  where ymd >= '20230501' and ymd <= '20230502'
) b
on a.uid = b.uid and a.ymd = b.ymd;

-- 代码3
explain dependency
select a.uid from temp.user_info_all a
left outer join (
	select uid,ymd from temp.user_act_info
  where ymd >= '20230501' and ymd <= '20230502'
) b
on a.uid = b.uid and a.ymd = b.ymd;

执行结果内容:

// 代码1 ,左右表都进行了全表扫描
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230430"},{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230503"},{"partitionName":"temp@user_info_all@ymd=20230504"},{"partitionName":"temp@user_info_all@ymd=20230505"},{"partitionName":"temp@user_info_all@ymd=20230529"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230503"},{"partitionName":"temp@user_act_info@ymd=20230606"}]}

//代码2,左右表都进行了过滤
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"}]}

//代码3,右表都进行了过滤
{"input_tables":[{"tablename":"temp@user_info_all","tabletype":"MANAGED_TABLE"},{"tablename":"temp@user_act_info","tabletype":"MANAGED_TABLE"}],"input_partitions":[{"partitionName":"temp@user_act_info@ymd=20230501"},{"partitionName":"temp@user_act_info@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230430"},{"partitionName":"temp@user_info_all@ymd=20230501"},{"partitionName":"temp@user_info_all@ymd=20230502"},{"partitionName":"temp@user_info_all@ymd=20230503"},{"partitionName":"temp@user_info_all@ymd=20230504"},{"partitionName":"temp@user_info_all@ymd=20230505"},{"partitionName":"temp@user_info_all@ymd=20230529"}]}

可以看到left outer join对右表过滤数据的优化中代码2是最优,代码3次之,代码1最差。

3.查看SQL操作涉及到的相关权限信息

通过explain authorization可以知道当前SQL访问的数据来源(INPUTS) 和数据输出(OUTPUTS),以及当前Hive的访问用户 (CURRENT_USER)和操作(OPERATION)。

可以看以下实例:

例8 使用explain authorization查看权限相关信息。

explain authorization
select a.uid from temp.user_info_all a
left outer join temp.user_act_info b
on a.uid = b.uid and a.ymd = b.ymd 
where a.ymd >= '20230501' and a.ymd <= '20230502';

执行结果:

INPUTS: 
  temp@user_info_all
  temp@user_act_info
  temp@user_info_all@ymd=20230501
  temp@user_info_all@ymd=20230502
  temp@user_act_info@ymd=20230501
  temp@user_act_info@ymd=20230502
OUTPUTS: 
  hdfs://nameservice1/tmp/hive/hdfs/a88cc133-c310-4129-bfa0-28011ac23904/hive_2023-06-07_19-42-55_464_2777807904847671424-1/-mr-10000
CURRENT_USER: 
  hdfs
OPERATION: 
  QUERY
AUTHORIZATION_FAILURES: 
  Permission denied: Principal [name=hdfs, type=USER] does not have following privileges for operation QUERY [[SELECT] on Object [type=TABLE_OR_VIEW, name=temp.user_act_info], [SELECT] on Object [type=TABLE_OR_VIEW, name=temp.user_info_all]]

从上面的信息可知:

上面案例的数据来源是temp数据库中的 user_info_all表和user_act_info表;

数据的输出路径是hdfs://nameservice1/tmp/hive/hdfs/a88cc133-c310-4129-bfa0-28011ac23904/hive_2023-06-07_19-42-55_464_2777807904847671424-1/-mr-10000;

当前的操作用户是hdfs,操作是查询(QUERY);

观察上面的信息我们还会看到AUTHORIZATION_FAILURES信息,提示对当前的输入没有查询权限,但如果运行上面的SQL的话也能够正常运行。为什么会出现这种情况?Hive在默认不配置权限管理的情况下不进行权限验证,所有的用户在Hive里面都是超级管理员,即使不对特定的用户进行赋权,也能够正常查询。

通过上面对explain相关参数的介绍,可以发现explain中有很多值得我们去研究的内容,读懂 explain 的执行计划有利于我们优化Hive SQL,同时也能提升我们对SQL的掌控力。

下一期:Hive执行计划之什么是hiveSQL向量化模式及优化详解

按例,欢迎点击此处关注我的个人公众号,交流更多知识。

后台回复关键字 hive,随机赠送一本鲁边备注版珍藏大数据书籍。

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

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

相关文章

RocketMQ-Request-Reply特性

源码版本号:版本号:4.9.4 使用场景 随着服务规模的扩大&#xff0c;单机服务无法满足性能和容量的要求&#xff0c;此时需要将服务拆分为更小粒度的服务或者部署多个服务实例构成集群来提供服务。在分布式场景下&#xff0c;RPC是最常用的联机调用的方式。 在构建分布式应用…

高考季,17岁VS人工智能,谁的作文更胜一筹?

又到一年高考日。想起十二年前我也曾和众多莘莘学子一样,在这场人生的史诗里挣扎奋斗。 那时的我满怀着期待和焦虑,站在人生的岔口,茫然纠结该循哪条道路。十二年光阴荏苒,岁月如梭, 如今我已不复当年学子的面容,更无法回首当时的迷茫与彷徨。 时过境迁,我如今以另一种身份再…

flask+scrapy

管道数据库 class SpiderBookPipeline:def __init__(self):host localhostuser rootpassword hdp020820db 警察大学信息检索self.conn pymysql.connect(hosthost, useruser, passwordpassword, dbdb)self.cursor self.conn.cursor()def process_item(self, item, spider…

【Python】Python系列教程-- Python3 元组(十三)

文章目录 前言访问元组修改元组删除元组元组运算符元组索引&#xff0c;截取元组内置函数关于元组是不可变的 前言 往期回顾&#xff1a; Python系列教程–Python3介绍&#xff08;一&#xff09;Python系列教程–Python3 环境搭建&#xff08;二&#xff09;Python系列教程–…

项目中的Echarts图表统计

数据可视化 一、Echarts二、前端&#xff08;VueEcharts&#xff09;HomeView.vue&#xff08;完整代码&#xff09; 三、后端&#xff08;SpringBootMyBatis&#xff09;BorrowController.javaIBorrowService.javaBorrowService.javadatetimeToDateStr()函数countList()函数 B…

同样是产品经理 段位差别大

同样是产品经理&#xff0c;段位差别大 趣讲大白话&#xff1a;做人的差距大 【趣讲信息科技189期】 **************************** 市场越内卷 对产品的要求越来越高 不管叫不叫产品经理这个头衔 产品开发的重要性不会降低 《人人都是产品经理》总结的段位 姑且一看&#xff…

java线程多线程并发

文章目录 对java线程的认识wait&#xff08;&#xff09;和sleep&#xff08;&#xff09;区别&#xff1f;wait&#xff0c;notify为什么要放在同步代码块中&#xff1f; 多线程**什么时候使用多线程**&#xff1a;**多线程的优缺点**&#xff1a;**线程安全问题**&#xff1a…

MATLAB应用

目录 网站 智能图像色彩缩减和量化 网站 https://yarpiz.com/ 智能图像色彩缩减和量化 使用智能聚类方法&#xff1a;&#xff08;a&#xff09;k均值算法&#xff0c;&#xff08;b&#xff09;模糊c均值聚类&#xff08;FCM&#xff09;和&#xff08;c&#xff09;自组织神…

Mysql—存储过程

简介 存储过程就是类似于MySQL触发器&#xff0c;经过事先编写好相应语句&#xff0c;通过编译后存储在数据库上。触发器不需要手动调用即可实现相应SQL功能。MySQL存储过程&#xff0c;需要自己去调用得到相应的结果。 语法 创建存储过程 CREATE DEFINER CURRENT_USER PR…

git---->团队开发神器,一篇文章直接掌握

git---->团队开发神器&#xff0c;一篇文章直接掌握 一 学习git的原因概念版本的概念1 版本控制软件的基础功能2 集中式版本控制软件3 分布式版本控制 二 git的安装三 GitHub Desktop的使用四 团队操作五 中央服务器--github从github上下载文件到本地仓库传输文件 六 国内中…

chatgpt赋能python:Python如何实现自增

Python如何实现自增 在Python编程中&#xff0c;自增是一种非常常用的操作&#xff0c;它可以让我们在循环、计数等场景中更加方便地进行操作。实际上&#xff0c;在Python中&#xff0c;实现自增非常简单&#xff0c;本文将介绍Python中常用的自增操作&#xff0c;并分享自增…

时间复杂度 空间复杂度

概览 时间复杂度与空间复杂度的作用是在衡量一个算法的优劣性&#xff0c;以及在二者之间进行权衡&#xff0c;寻找二者的平衡点。 时间复杂度是指执行算法所需时间的增长率&#xff0c;而空间复杂度则是指执行算法所需存储空间的增长率。 高时间复杂度的算法可能需要在短时间…

LayUI前框框架普及版

LayUI 一、课程目标 1. 【了解】LayUI框架 2. 【理解】LayUI基础使用 3. 【掌握】LayUI页面元素 4. 【掌握】LayUI内置模块二、LayUI基本使用 2.1 概念 layui&#xff08;谐音&#xff1a;类UI) 是一款采用自身模块规范编写的前端 UI 框架&#xff0…

Nginx+Tomcat 负载均衡、动静分离

目录 一、Nginx代理服务器概念 1.正向代理 2.反向代理 二、动静分离 三、负载均衡 四、Nginx七层代理实验 1.部署Nginx服务 2. 部署Tomcat服务 2.1在192.168.88.50 虚拟机上部署双实例 2.2在192.168.88.60 上部署Tomcat服务器3 3.动静分离配置 3.1Tomcat1 server 配…

RecyclerView的回收缓存均由内部类Recycler完成

1. RecyclerView的三级缓存 通常在RecyclerView中存在着四级缓存&#xff0c;从低到高分别为&#xff1a; 可直接重复使用的临时缓存&#xff08;mAttachedScrap/mChangedScrap&#xff09; mAttachedScrap中缓存的是屏幕中可见范围的ViewHoldermChangedScrap只能在预布局状态…

Material—— 常用材质节点

目录 Coordinates Absolute World Position Actor Position Object Position Utility SphereMask Coordinates 表示坐标类的节点&#xff1b; Absolute World Position 别名为WorldPosition&#xff0c;此节点输出当前像素在世界空间内的位置&#xff1b;常用于查找相机到…

作为过来人:有什么话想对当年高考前的自己说

目录 引言千人千面-有什么话想对当年高考前的自己说怀念高中&#xff0c;数学太难多考一分&#xff0c;人生就会不一样一定要勇敢&#xff0c;不止高考别把高考不当回事6的我没话说想到啥就去做别选**大学/专业强烈想出名的拖鞋哥英语全选C&#xff0c;理综要细心会的全做对当时…

Spring - 注解开发

文章目录 Spring的注解开发一、Bean 基本注解开发1.1 Component Bean的配置1.2 其他注解配置Bean1.3 Component 衍生注解 二、Bean依赖注入注解开发2.1 Value2.2 Autowired2.3 Qualifier2.4 Resource 三、非自定义注解开发3.1 无参非自定义注解开发3.2 有参非自定义注解开发 四…

Domino 14新内核

大家好&#xff0c;才是真的好。 还记得去年&#xff0c;我们不断跟进而放出的Notes/Domino产品路线图吗&#xff1f;是的&#xff0c;HCL正在按照产品路线图稳步推进&#xff0c;而很多人提出的idea&#xff0c;也逐步加入到产品中&#xff0c;等会我们也会聊到。 我最喜欢这…

MySQL安装-Linux版

MySQL-Linux版安装 1、准备一台Linux服务器 云服务器或者虚拟机都可以&#xff1b; Linux的版本为 CentOS7&#xff1b; 2、 下载Linux版MySQL安装包 下载地址 3、上传MySQL安装包 使用FinalShell软件上传即可&#xff01; 4、 创建目录,并解压 mkdir mysqltar -xvf my…