Hive从入门到精通,HQL硬核整理四万字,全面总结,附详细解析,赶紧收藏吧!!

Posted 北慕辰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hive从入门到精通,HQL硬核整理四万字,全面总结,附详细解析,赶紧收藏吧!!相关的知识,希望对你有一定的参考价值。



往期好文推荐:
🔶🔷Hadoop深入浅出 ——三大组件HDFS、MapReduce、Yarn框架结构的深入解析式地详细学习【建议收藏!!!】

🔶🔷Redis从青铜到王者,从环境搭建到熟练使用,看这一篇就够了,超全整理详细解析,赶紧收藏吧!!!

🔶🔷硬核整理四万字,学会数据库只要一篇就够了,盘它!MySQL基本操作以及常用的内置函数汇总整理

🔶🔷Redis主从复制 以及 集群搭建 详细步骤解析,赶快收藏练手吧!

🔶🔷Hadoop集群HDFS、YARN高可用HA详细配置步骤说明,附Zookeeper搭建详细步骤【建议收藏!!!】

🔶🔷SQL进阶-深入理解MySQL,JDBC连接MySQL实现增删改查,赶快收藏吧!

🔶🔷初识鸿蒙OS,你好,HarmonyOS!

🔶🔷【小白学Java】D25 》》》Java中的各种集合大汇总,学习整理

🔶🔷hadoop入门简介


💜🧡💛制作不易,各位大佬们给点鼓励!
🧡💛💚点赞👍 ➕ 收藏⭐ ➕ 关注✅
💛💚💙欢迎各位大佬指教,一键三连走起!

》》》本篇文章主要是与大家分享,Hive的一些常见操作,分区,分桶,窗口函数等等,以及Hive的HQL的使用练习,如有错误,烦请大佬指教。希望大家能够喜欢!


目录

        🧡一、了解Hive
                💜1、Hive的概念及架构
                💜2、Hive与传统数据库比较
                💜3、Hive的数据存储格式
                💜4、Hive操作客户端
        🧡二、Hive的基本语法
                💜1、Hive建表语法
                💜2、Hive加载数据
                💜3、Hive 内部表(Managed tables)vs 外部表(External tables)
                💜4、Hive 分区
                💜5、Hive动态分区
                💜6、Hive分桶
                💜7、Hive连接JDBC
        🧡三、Hive的数据类型
                💜1、基本数据类型
                💜2、日期类型
                💜3、复杂数据类型
        🧡四、Hive HQL使用语法
                💜1、HQL语法-DDL
                💜2、HQL语法-DML
        🧡五、Hive HQL使用注意
        🧡六、Hive 的函数使用
                💜1、Hive-常用函数
                        💚(1)关系运算
                        💚(2)数值计算
                        💚(3) 条件函数
                        💚(4)日期函数
                        💚(5) 字符串函数
                💜2、Hive-高级函数
                        💚(1)窗口函数(开窗函数):用户分组中开窗
                        💚(2)Hive 行转列
                        💚(3)Hive 列转行
                        💚(4)Hive自定义函数UserDefineFunction
                                ⭕ UDF:一进一出
                                ⭕UDTF:一进多出
                                ⭕UDAF:多进一出
                💜3、Hive 中的wordCount
        🧡七、Hive 的Shell使用


一、了解Hive

1、Hive的概念及架构

                          点我返回目录

        Hive 是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL ),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类 SQL 查询语言,称为 HQL ,它允许熟悉 SQL 的用户查询数据。同时,这个语言也允许熟悉 MapReduce 的开发者开发自定义的 mapper 和 reducer 来处理内建的 mapper 和 reducer 无法完成的复杂的分析工作。Hive是SQL解析引擎,它将SQL语句转译成Map/Reduce Job然后在Hadoop执行。Hive的表其实就是HDFS的目录,按表名把文件夹分开。如果是分区表,则分区值是子文件夹,可以直接在Map/Reduce Job里使用这些数据。Hive相当于hadoop的客户端工具,部署时不一定放在集群管理节点中,也可以放在某个节点上。

数据仓库,英文名称为Data Warehouse,可简写为DW或DWH。数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合。它出于分析性报告和决策支持目的而创建。为需要业务智能的企业,提供指导业务流程改进、监视时间、成本、质量以及控制。

Hive的版本介绍:
0.13和.14版本,稳定版本,但是不支持更新删除操作。
1.2.1和1.2.2 版本,稳定版本,为Hive2版本(是主流版本)
1.2.1的程序只能连接hive1.2.1 的hiveserver2

2、Hive与传统数据库比较

                          点我返回目录

查询语言HiveQLSQL
数据存储位置HDFSRaw Device or 本地FS
数据格式用户定义系统决定
数据更新不支持(1.x以后版本支持)支持
索引新版本有,但弱
执行MapReduceExecutor
执行延迟
可扩展性
数据规模
  1. 查询语言。类 SQL 的查询语言 HQL。熟悉 SQL 开发的开发者可以很方便的使用 Hive 进行开发。
  2. 数据存储位置。所有 Hive 的数据都是存储在 HDFS 中的。而数据库则可以将数据保存在块设备或者本地文件系统中。
  3. 数据格式。Hive 中没有定义专门的数据格式。而在数据库中,所有数据都会按照一定的组织存储,因此,数据库加载数据的过程会比较耗时。
  4. 数据更新。Hive 对数据的改写和添加比较弱化,0.14版本之后支持,需要启动配置项。而数据库中的数据通常是需要经常进行修改的。
  5. 索引。Hive 在加载数据的过程中不会对数据进行任何处理。因此访问延迟较高。数据库可以有很高的效率,较低的延迟。由于数据的访问延迟较高,决定了 Hive 不适合在线数据查询。
  6. 执行计算。Hive 中执行是通过 MapReduce 来实现的而数据库通常有自己的执行引擎。
  7. 数据规模。由于 Hive 建立在集群上并可以利用 MapReduce 进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。

3、Hive的数据存储格式

                          点我返回目录

  • Hive的数据存储基于Hadoop HDFS。

  • Hive没有专门的数据文件格式,常见的有以下几种:TEXTFILE、SEQUENCEFILE、AVRO、RCFILEORCFILEPARQUET


下面我们详细的看一下Hive的常见数据格式:


  • TextFile:
             TEXTFILE 即正常的文本格式,是Hive默认文件存储格式,因为大多数情况下源数据文件都是以text文件格式保存(便于查看验数和防止乱码)。此种格式的表文件在HDFS上是明文,可用hadoop fs -cat命令查看,从HDFS上get下来后也可以直接读取。
             TEXTFILE 存储文件默认每一行就是一条记录,可以指定任意的分隔符进行字段间的分割。但这个格式无压缩,需要的存储空间很大。 虽然可以结合Gzip、Bzip2、Snappy等使用,使用这种方式,Hive不会对数据进行切分,从而无法对数据进行并行操作。一般只有与其他系统由数据交互的接口表采用TEXTFILE 格式,其他事实表和维度表都不建议使用。

  • RCFile:
            Record Columnar的缩写。是Hadoop中第一个列文件格式。 能够很好的压缩和快速的查询性能。通常写操作比较慢,比非列形式的文件格式需要更多的内存空间和计算量。 RCFile是一种行列存储相结合的存储方式。 首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据列式存储,有利于数据压缩和快速的列存取。

  • ORCFile:
            Hive从0.11版本开始提供了ORC的文件格式,ORC文件不仅仅是一种列式文件存储格式,最重要的是有着很高的压缩比,并且对于MapReduce来说是可切分(Split)的。因此,在Hive中使用ORC作为表的文件存储格式,不仅可以很大程度的节省HDFS存储资源,而且对数据的查询和处理性能有着非常大的提升,因为ORC较其他文件格式压缩比高,查询任务的输入数据量减少,使用的Task也就减少了。ORC能很大程度的节省存储和计算资源,但它在读写时候需要消耗额外的CPU资源来压缩和解压缩,当然这部分的CPU消耗是非常少的。

  • Parquet:
             通常我们使用关系数据库存储结构化数据,而关系数据库中使用数据模型都是扁平式的,遇到诸如List、Map和自定义Struct的时候就需要用户在应用层解析。但是在大数据环境下,通常数据的来源是服务端的埋点数据,很可能需要把程序中的某些对象内容作为输出的一部分,而每一个对象都可能是嵌套的,所以如果能够原生的支持这种数据,这样在查询的时候就不需要额外的解析便能获得想要的结果。Parquet的灵感来自于2010年Google发表的Dremel论文,文中介绍了一种支持嵌套结构的存储格式,并且使用了列式存储的方式提升查询性能。Parquet仅仅是一种存储格式,它是语言、平台无关的,并且不需要和任何一种数据处理框架绑定。这也是parquet相较于orc的仅有优势支持嵌套结构。Parquet 没有太多其他可圈可点的地方,比如他不支持update操作(数据写成后不可修改),不支持ACID等.

  • SEQUENCEFILE:
             SequenceFile是Hadoop API 提供的一种二进制文件,它将数据以<key,value>的形式序列化到文件中。 这种二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,不过它的key为空,使用value 存放实际的值, 这样是为了避免MR 在运行map 阶段的排序过程。 SequenceFile支持三种压缩选择:NONE, RECORD, BLOCK。 Record压缩率低,一般建议使用BLOCK压缩。 SequenceFile最重要的优点就是Hadoop原生支持较好,有API,但除此之外平平无奇,实际生产中不会使用。

  • AVRO:
             Avro是一种用于支持数据密集型的二进制文件格式。它的文件格式更为紧凑,若要读取大量数据时,Avro能够提供更好的序列化和反序列化性能。并且Avro数据文件天生是带Schema定义的,所以它不需要开发者在API 级别实现自己的Writable对象。Avro提供的机制使动态语言可以方便地处理Avro数据。最近多个Hadoop 子项目都支持Avro 数据格式,如Pig 、Hive、Flume、Sqoop和Hcatalog。

其中的TextFileRCFileORCParquet为Hive最常用的四大存储格式
它们的 存储效率及执行速度比较如下:
    ORCFile存储文件读操作效率最高,耗时比较(ORC<Parquet<RCFile<TextFile)
    ORCFile存储文件占用空间少,压缩效率高(ORC<Parquet<RCFile<TextFile)

4、Hive操作客户端

                          点我返回目录

常用的客户端有两个:CLI,JDBC/ODBC

  • CLI,即Shell命令行

  • JDBC/ODBC 是 Hive 的Java,与使用传统数据库JDBC的方式类似。

  1. Hive 将元数据存储在数据库中(metastore),目前只支持 mysql、derby。 Hive 中的元数据包括表的名字,表的列和分区及其属性,表的属性(是否为外部表等),表的数据所在目录等;由解释器、编译器、优化器完成 HQL 查询语句从词法分析、语法分析、编译、优化以及查询计划(plan)的生成。生成的查询计划存储在 HDFS 中,并在随后由 MapReduce 调用执行。

  2. Hive 的数据存储在 HDFS 中,大部分的查询由 MapReduce 完成(包含 * 的查询,比如 select * from table 不会生成 MapRedcue 任务)

Hive的metastore

metastore是hive元数据的集中存放地。
metastore默认使用内嵌的derby数据库作为存储引擎
Derby引擎的缺点:一次只能打开一个会话
使用MySQL作为外置存储引擎,可以多用户同时访问`

元数据库详解见:查看mysql SDS表和TBLS表
连接地址:https://blog.csdn.net/haozhugogo/article/details/73274832

二、Hive的基本语法

1、Hive建表语法

                          点我返回目录

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
  // 定义字段名,字段类型
  [(col_name data_type [COMMENT col_comment], ...)]
  // 给表加上注解
  [COMMENT table_comment]
  // 分区
  [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
  // 分桶
  [CLUSTERED BY (col_name, col_name, ...) 
  // 设置排序字段 升序、降序
  [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
  [
  	// 指定设置行、列分隔符 
   [ROW FORMAT row_format] 
   // 指定Hive储存格式:textFile、rcFile、SequenceFile 默认为:textFile
   [STORED AS file_format]
   
   | STORED BY 'storage.handler.class.name' [ WITH SERDEPROPERTIES (...) ]  (Note:  only available starting with 0.6.0)
  ]
  // 指定储存位置
  [LOCATION hdfs_path]
  // 跟外部表配合使用,比如:映射HBase表,然后可以使用HQL对hbase数据进行查询,当然速度比较慢
  [TBLPROPERTIES (property_name=property_value, ...)]  (Note:  only available starting with 0.6.0)
  [AS select_statement]  (Note: this feature is only available starting with 0.5.0.)

建表格式1:全部使用默认建表方式

                          点我返回目录

create table students
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','; 
// 必选,指定列分隔符 

建表格式2:指定location (这种方式也比较常用)

                          点我返回目录

create table students2
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/input1'; 
// 指定Hive表的数据的存储位置,一般在数据已经上传到HDFS,想要直接使用,会指定Location,
//通常Locaion会跟外部表一起使用,内部表一般使用默认的location

建表格式3:指定存储格式

                          点我返回目录

create table students3
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS rcfile; 
// 指定储存格式为rcfile,inputFormat:RCFileInputFormat,outputFormat:RCFileOutputFormat,
//如果不指定,默认为textfile,
//注意:除textfile以外,其他的存储格式的数据都不能直接加载,需要使用从表加载的方式。

建表格式4:create table xxxx as select_statement(SQL语句) (这种方式比较常用)

                          点我返回目录

注意:

  1. 新建表不允许是外部表
  2. select后面表需要是已经存在的表,建表同时会加载数据。
  3. 会启动mapreduce任务去读取源表数据写入新表
create table students4 as select * from students2;

建表格式5:create table xxxx like table_name 只想建表,不需要加载数据

create table students5 like students;

2、Hive加载数据

                          点我返回目录

1)、使用hdfs dfs -put '本地数据' 'hive表对应的HDFS目录下'

2)、使用 load data inpath

        从hdfs导入数据,路径可以是目录,会将目录下所有文件导入,但是文件格式必须一致

// 将HDFS上的/input1目录下面的数据 移动至 students表对应的HDFS目录下
// 注意是 移动!移动!移动!
load data inpath '/input1/students.txt' into table students;
// 清空表
truncate table students;

从本地文件系统导入

// 加上 local 关键字 可以将Linux本地目录下的文件 上传到 hive表对应HDFS 目录下 原文件不会被删除
load data local inpath '/usr/local/soft/data/students.txt' into table students;
// overwrite 覆盖加载
load data local inpath '/usr/local/soft/data/students.txt' overwrite into table students;

3)、create table xxx as SQL语句,表对表加载

4)、insert into table xxxx SQL语句 (没有as),表对表加载:

// 将 students表的数据插入到students2 
//这是复制 不是移动 students表中的表中的数据不会丢失
insert into table students2 select * from students;

// 覆盖插入 把into 换成 overwrite
insert overwrite table students2 select * from students;

注意:
1,如果建表语句没有指定存储路径,不管是外部表还是内部表,存储路径都是会默认在hive/warehouse/xx.db/表名的目录下。
加载的数据如果在HDFS上会移动到该表的存储目录下。注意是移动,不是复制
2,删除外部表,文件不会删除,对应目录也不会删除

3、Hive 内部表(Managed tables)vs 外部表(External tables)

                          点我返回目录

外部表和普通表的区别

  1. 外部表的路径可以自定义,内部表的路径需要在 hive/warehouse/目录下
  2. 删除表后,普通表数据文件和表信息都删除。外部表仅删除表信息

1)、建表语句:

// 内部表
create table students_internal
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/input2';

// 外部表
create external table students_external
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
LOCATION '/input3';

2)、加载数据:

hive> dfs -put /usr/local/soft/data/students.txt /input2/;
hive> dfs -put /usr/local/soft/data/students.txt /input3/;

3)、删除表:

hive> drop table students_internal;
Moved: 'hdfs://master:9000/input2' to trash at: hdfs://master:9000/user/root/.Trash/Current
OK
Time taken: 0.474 seconds
hive> drop table students_external;
OK
Time taken: 0.09 seconds

1、可以看出,删除内部表的时候,表中的数据(HDFS上的文件)会被同表的元数据一起删除;删除外部表的时候,只会删除表的元数据,而不会删除表中的数据(HDFS上的文件)
2、一般在公司中,使用外部表多一点,因为数据可以需要被多个程序使用,避免误删,通常外部表会结合location一起使用
3、外部表还可以将其他数据源中的数据 映射到 hive中,比如说:hbase,ElasticSearch…
4、设计外部表的初衷就是 让 表的元数据 与 数据 解耦

4、Hive 分区

                          点我返回目录

        分区表实际上是在表的目录下在以分区命名,建子目录;作用:进行分区裁剪,避免全表扫描,减少MapReduce处理的数据量,提高效率
        一般在公司的hive中,所有的表基本上都是分区表,通常按日期分区、地域分区;分区表在使用的时候记得加上分区字段;分区也不是越多越好,一般不超过3级,根据实际业务衡量

分区的概念和分区表:
分区表指的是在创建表时指定分区空间,实际上就是在hdfs上表的目录下再创建子目录。
在使用数据时如果指定了需要访问的分区名称,则只会读取相应的分区,避免全表扫描,提高查询效率。

1)、建立分区表:

create external table students_pt1
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
PARTITIONED BY(pt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

2)、增加一个分区:

alter table students_pt1 add partition(pt='20210904');

3)、删除一个分区:

alter table students_pt drop partition(pt='20210904');

4)、查看某个表的所有分区

 // 推荐这种方式(直接从元数据中获取分区信息)
show partitions students_pt;

// 不推荐
select distinct pt from students_pt; 

5)、往分区中插入数据:

insert into table students_pt partition(pt='20210902') select * from students;

load data local inpath '/usr/local/soft/data/students.txt' into table students_pt partition(pt='20210902');

6)、查询某个分区的数据:

// 全表扫描,不推荐,效率低
select count(*) from students_pt;


// 使用where条件进行分区裁剪,避免了全表扫描,效率高
select count(*) from students_pt where pt='20210101';


// 也可以在where条件中使用非等值判断
select count(*) from students_pt where pt<='20210112' and pt>='20210110';

5、Hive动态分区

                          点我返回目录

有的时候我们原始表中的数据里面包含了 ‘‘日期字段 dt’’,我们需要根据dt中不同的日期,分为不同的分区,将原始表改造成分区表。

hive默认不开启动态分区

动态分区根据数据中某几列的不同的取值 划分 不同的分区

# 表示开启动态分区
hive> set hive.exec.dynamic.partition=true;

# 表示动态分区模式:strict(需要配合静态分区一起使用)、nostrict

# strict: insert into table students_pt partition(dt='anhui',pt) select ......,pt from students;
hive> set hive.exec.dynamic.partition.mode=nostrict;

# 表示支持的最大的分区数量为1000,可以根据业务自己调整
hive> set hive.exec.max.dynamic.partitions.pernode=1000;

1)、建立原始表并加载数据

create table students_dt
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string,
    dt string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

2)、建立分区表并加载数据

create table students_dt_p
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
PARTITIONED BY(dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

3)、使用动态分区插入数据

// 分区字段需要放在 select 的最后,如果有多个分区字段 同理,
//它是按位置匹配,不是按名字匹配
insert into table students_dt_p partition(dt) select id,name,age,gender,clazz,dt from students_dt;

// 比如下面这条语句会使用age作为分区字段,而不会使用student_dt中的dt作为分区字段
insert into table students_dt_p partition(dt) select id,name,age,gender,dt,age from students_dt;

4)、多级分区

create table students_year_month
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string,
    year string,
    month string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

create table students_year_month_pt
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
PARTITIONED BY(year string,month string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

insert into table students_year_month_pt partition(year,month) select id,name,age,gender,clazz,year,month from students_year_month;

有关分区好文分享:上单讲分区:https://developer.aliyun.com/article/81775

6、Hive分桶

                          点我返回目录

        分桶实际上是对文件(数据)的进一步切分Hive默认关闭分桶分桶的作用:在往分桶表中插入数据的时候,会根据 clustered by 指定的字段 进行hash分组 对指定的buckets个数 进行取余,进而可以将数据分割成buckets个数个文件,以达到数据均匀分布,可以解决Map端的“数据倾斜”问题,方便我们取抽样数据,提高Map join效率;分桶字段 需要根据业务进行设定

1)、开启分桶开关

hive> set hive.enforce.bucketing=true;

2)、建立分桶表

create table students_buks
(
    id bigint,
    name string,
    age int,
    gender string,
    clazz string
)
CLUSTERED BY (clazz) into 12 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','; 

3)、往分桶表中插入数据

// 直接使用load data 并不能将数据打散
load data local inpath '/usr/local/soft/data/students.txt' into table students_buks;

// 需要使用下面这种方式插入数据,才能使分桶表真正发挥作用
insert into students_buks select * from students;

Hive关于分桶好文分享, Hive分桶表的使用场景以及优缺点分析:https://zhuanlan.zhihu.com/p/93728864

7、Hive连接JDBC

                          点我返回目录

1)、启动hiveserver2的服务

hive --service hiveserver2 &

2)、 新建maven项目并添加两个依赖

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.hive/hive-jdbc -->
    <dependency>
        <groupId>org.apache.hive</groupId>
        <artifactId>hive-jdbc</artifactId>
        <version>1.2.1</version>
    </dependency>

3)、 编写JDBC代码

import java.sql.*;

public class HiveJDBC {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName("org.apache.hive.jdbc.HiveDriver");
        Connection conn = DriverManager.getConnection("jdbc:hive2://master:10000/test3");
        Statement stat = conn.createStatement();
        ResultSet rs = stat.executeQuery("select * from students limit 10");
        while (rs.next以上是关于Hive从入门到精通,HQL硬核整理四万字,全面总结,附详细解析,赶紧收藏吧!!的主要内容,如果未能解决你的问题,请参考以下文章

最强最全面的Hive SQL开发指南,超四万字全面解析

最强最全面的Hive SQL开发指南,超四万字全面解析

硬核整理四万字,学会数据库只要一篇就够了,盘它!MySQL基本操作以及常用的内置函数汇总整理

❤️爆肝四万字的MySQL总结全面整理+详细解释❤️

2 万字全面测评深度学习框架 PaddlePaddleTensorFlow 和 Keras | 程序员硬核评测

很全面的 Docker 教程,从入门到精通(建议收藏)