1 Hive

Hive 是 FaceBook 开源的一款基于 Hadoop 数据仓库工具,它可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。

The Apache Hive ™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL 。

1.1 Hive 优缺点

1.1.1 优点
  1. 操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)。

  2. 避免了去写MapReduce,减少开发人员的学习成本。

  3. Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合。

  4. Hive优势在于处理大数据,对于处理小数据没有优势,因为Hive的执行延迟比较高。

  5. Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。

1.1.2 缺点
  1. Hive 的 HQL 表达能力有限,无法表达迭代式算法,不擅长数据挖掘方面。

  2. Hive 的效率比较低,Hive 自动生成的 MapReduce 作业,通常情况下不够智能化。

  3. Hive 查询无法做到跟 MySQL 一样毫秒返回。

1.2 Hive 跟 MySQL 比较

1.2.1 对比

Hive 采用了类SQL 的查询语言 HQL(Hive Query Language),因此很容易将 Hive 理解为数据库。其实从结构上来看,Hive 和数据库除了拥有类似的查询语言,再无类似之处。本文将从多个方面来阐述 Hive 和数据库的差异。数据库可以用在 Online 的应用中,但是Hive 是为数据仓库而设计的,清楚这一点,有助于从应用角度理解 Hive 的特性。

方向 Hive MySQL
应用方向 数仓 Online
查询语言 HQL SQL
数据存储位置 HDFS 本地文件系统
数据更新 读多写少,无法修改 正常CRUD
索引 无索引,暴力查询 各种索引
执行 底层MapReduce 自己执行引擎
延迟 高延迟 低延迟
可扩展性 优秀扩展能力 扩展力有限
数据量 超大规模 小规模

1.2.2 Hive 不支持那些

  1. 支持等值查询,不支持非等值连接

  2. 支持 and 多条件过滤,不支持 or 多条件过滤。

  3. 不支持 update 跟 delete。

1.3 Hive 底层

Hive 底层是 MapReduce 计算框架,Hive 只是将通读性强且容易编程的SQL语句通过 Hive 软件转换成MapReduce 程序在集群上执行,Hive 可以看做 MapReduce 客户端。操作的数据还是存储在HDFS上的,而用户定义的表结构等元信息被存储到 MySQL 上了。以前要写八股文 MapReduce 程序,现在只需要HQL查询就可!

Hive整体框架
  1. 用户接口 Client

CLI(hive shell)、JDBC/ODBC(java访问hive)、WEBUI(浏览器访问hive)

  1. 元数据 Metastore

  2. 元数据包括 表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等。

  3. 默认存储在自带的derby数据库中(单客户连接),推荐使用MySQL存储Metastore。

  4. Hadoop
    使用HDFS进行存储,使用MapReduce进行计算。

  1. 驱动器 Driver

  1. 解析器 SQL Parser:将SQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。

  2. 编译器 Physical Plan:将AST编译生成逻辑执行计划。

  3. 优化器 Query Optimizer:对逻辑执行计划进行优化。

  4. 执行器 Execution:把逻辑执行计划转换成可以运行的物理计划。对于Hive来说就是MR/Spark。

HQL执行流程

不要把 Hive 想的多么神秘,你可以用简单的load方式将数据加载到创建的表里,也可以直接用hadoop指令将数据放入到指定目录,这两种方式都可以直接让你通过SQL查询到数据。

1.4  HQL 底层执行举例

1.4.1 Join

Join流程
1.4.2 group by

group by 流程
1.4.3 distinct

distinct 流程

2 开窗函数

有时想要同时显示聚集前后的数据,这时引入了窗口函数,在SQL处理中,窗口函数都是最后一步执行,而且仅位于 Order by 字句之前。

2.1  数据准备

name,orderdate,cost
jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94

建表 导数据

create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/opt/module/datas/business.txt" into table business;

2.2 用法

相关函数说明

  1. OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化

  2. CURRENT ROW:当前行

  3. n PRECEDING:往前 n 行数据

  4. n FOLLOWING:往后 n 行数据

  5. UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING 表示到后面的终点

上面写 over 里面,下面写 over 前面。

  1. LAG(col,n):往前 n 行数据

  2. LEAD(col,n):往后 n 行数据

  3. NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE 返回此行所属的组的编号。注意:n必须为int类型。

2.3 开窗函数demo

  1. 查询在2017年4月份购买过的顾客及总人数

select name,count(*) over() from business where substring(orderdate,1,7) = '2017-04' group by name;
结果:
mart    2
jack    2
  1. 查询顾客的购买明细及月购买总额

select name,orderdate,cost,sum(cost) over(partition by month(orderdate))
from business;
解释:按照月划分数据  然后统计这个月的cost总和
jack    2017-01-01  10  205
jack    2017-01-08  55  205
tony    2017-01-07  50  205
jack    2017-01-05  46  205
tony    2017-01-04  29  205
tony    2017-01-02  15  205
jack    2017-02-03  23  23
mart    2017-04-13  94  341
jack    2017-04-06  42  341
mart    2017-04-11  75  341
mart    2017-04-09  68  341
mart    2017-04-08  62  341
neil    2017-05-10  12  12
neil    2017-06-12  80  80
  1. 查看顾客上次的购买时间

select name,orderdate,cost,
lag(orderdate,1,'defaulttime') over(partition by name order by orderdate ) as time1,
lag(orderdate,2,'defaulttime') over (partition by name order by orderdate) as time2  from business;
结果 :
姓名      日期      价格  前一天日期    前两天日期
jack    2017-01-01  10  defaulttime defaulttime
jack    2017-01-05  46  2017-01-01  defaulttime
jack    2017-01-08  55  2017-01-05  2017-01-01
jack    2017-02-03  23  2017-01-08  2017-01-05
jack    2017-04-06  42  2017-02-03  2017-01-08
mart    2017-04-08  62  defaulttime defaulttime
mart    2017-04-09  68  2017-04-08  defaulttime
mart    2017-04-11  75  2017-04-09  2017-04-08
mart    2017-04-13  94  2017-04-11  2017-04-09
neil    2017-05-10  12  defaulttime defaulttime
neil    2017-06-12  80  2017-05-10  defaulttime
tony    2017-01-02  15  defaulttime defaulttime
tony    2017-01-04  29  2017-01-02  defaulttime
tony    2017-01-07  50  2017-01-04  2017-01-02
  1. 查询前20%时间的订单信息

 select * from (select name,orderdate,cost, ntile(5) over(order by orderdate) sorted from business ) t where sorted = 1;
结果 :
jack    2017-01-01  10  1
tony    2017-01-02  15  1
tony    2017-01-04  29  1
jack    2017-01-05  46  2
tony    2017-01-07  50  2
jack    2017-01-08  55  2
jack    2017-02-03  23  3
jack    2017-04-06  42  3
mart    2017-04-08  62  3
mart    2017-04-09  68  4
mart    2017-04-11  75  4
mart    2017-04-13  94  4
neil    2017-05-10  12  5
neil    2017-06-12  80  5

以下实验均关注最后一列

1. 所有行相加

select name,orderdate,cost,sum(cost) over() as sample1 from business;
结果 :
mart    2017-04-13  94  661
neil    2017-06-12  80  661
mart    2017-04-11  75  661
neil    2017-05-10  12  661
mart    2017-04-09  68  661

2. 按name分组,组内数据相加

select name,orderdate,cost,sum(cost) over(partition by name) as sample2
from business;
结果 :
jack    2017-01-05  46  176
jack    2017-01-08  55  176
jack    2017-01-01  10  176
jack    2017-04-06  42  176
jack    2017-02-03  23  176
...
tony    2017-01-04  29  94
tony    2017-01-02  15  94
tony    2017-01-07  50  94

3. 按name分组,组内数据累加

select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate) as sample3
from business;
跟下面类似
select name,orderdate,cost,
sum(cost) over(distribute by name sort by orderdate) as sample3
from business;
jack    2017-01-01  10  10
jack    2017-01-05  46  56
jack    2017-01-08  55  111
jack    2017-02-03  23  134
jack    2017-04-06  42  176
...

4. 和sample3一样,由起点到当前行的聚合

select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
between UNBOUNDED PRECEDING and current row ) as sample4
from business;
结果 :
jack    2017-01-01  10  10
jack    2017-01-05  46  56
jack    2017-01-08  55  111
jack    2017-02-03  23  134
jack    2017-04-06  42  176
...

5. 当前行和前面一行做聚合

select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
between 1 PRECEDING and current row) as sample5
from business;
结果 :
jack    2017-01-01  10  10
jack    2017-01-05  46  56 = 46 + 10
jack    2017-01-08  55  101 = 44 + 46
jack    2017-02-03  23  78  = 23 + 55
jack    2017-04-06  42  65  = 42 + 23
...
tony    2017-01-02  15  15
tony    2017-01-04  29  44
tony    2017-01-07  50  79

6. 当前行和前边一行及后面一行

select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
between 1 PRECEDING AND 1 FOLLOWING ) as sample6
from business;
结果 :
jack    2017-01-01  10  56  = 10 + 46
jack    2017-01-05  46  111 = 46 + 10 + 55
jack    2017-01-08  55  124 = 55 + 46 + 23
jack    2017-02-03  23  120 = 23 + 55 + 42
jack    2017-04-06  42  65  = 42 + 23
...
tony    2017-01-02  15  44
tony    2017-01-04  29  94
tony    2017-01-07  50  79

7. 当前行及后面所有行

select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 from business;
结果 :
jack    2017-01-01  10  176 = 10 + 46 + 55 + 23 + 42
jack    2017-01-05  46  166 = 46 + 55 + 23 + 42
jack    2017-01-08  55  120 = 55 + 23 + 42
jack    2017-02-03  23  65  =  23 + 42
jack    2017-04-06  42  42  =  42
mart    2017-04-08  62  299
mart    2017-04-09  68  237
mart    2017-04-11  75  169
mart    2017-04-13  94  94
neil    2017-05-10  12  92
neil    2017-06-12  80  80
tony    2017-01-02  15  94
tony    2017-01-04  29  79
tony    2017-01-07  50  50

2.4 Rank

函数说明

rank():排序相同时会重复,总数不会变
dense_rank():排序相同时会重复,总数会减少
row_number():会根据顺序计算

select name,subject,score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from score;
结果 :
name   subject score    rp      drp     rmp
孙悟空   数学    95      1       1       1
宋宋    数学    86      2       2       2
婷婷    数学    85      3       3       3
大海    数学    56      4       4       4
宋宋    英语    84      1       1       1
大海    英语    84      1       1       2
婷婷    英语    78      3(跳过2)2        3
孙悟空  英语    68      4       3(总数少)  4
大海    语文    94      1       1       1
孙悟空  语文    87      2        2        2
婷婷    语文    65      3       3       3
宋宋    语文    64      4       4       4

2.5 行转列

  1. CONCAT(string A, string B):

返回输入字符串连接后的结果,支持任意个输入字符串;

  1. CONCAT_WS(separator, str1, str2,…):
    特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将为 NULL。

  2. COLLECT_SET(col):
    只接受基本数据类型,主要作用是将某字段的值进行去重汇总,产生array类型字段。多行汇总成一个array类型。

2.6 列转行

  1. EXPLODE(col):

将hive一列中复杂的array或者map结构拆分成多行。

  1. LATERAL VIEW
    用法:LATERAL VIEW udtf(expression) table Alias AS columnAlias
    解释:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。

3 Hive 调优

3.1 MapJoin

如果不指定 MapJoin 或者不符合 MapJoin 的条件,那么 Hive 解析器会将 Join 操作转换成 Common Join,也就是在Reduce阶段完成join。容易发生数据倾斜。可以用 MapJoin 把小表全部加载到内存在map 端进行 join,避免 reducer 处理。

3.2 行列过滤

列处理:在SELECT时只拿需要的列,尽量使用分区过滤,少用SELECT *。
行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where后面,那么就会先全表关联,之后再过滤。

3.3 合理设置Map数跟Reduce数

3.3.1  map数不是越多越好

如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费 。而且,同时可执行的map数是受限的。此时我们就应该减少map数量。

3.3.2 Reduce数不是越多越好
  1. 过多的启动和初始化Reduce也会消耗时间和资源;

  2. 有多少个Reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;

  3. Reduce个数设置考虑这两个原则:处理大数据量利用合适的Reduce数;使单个Reduce任务处理数据量大小要合适;

3.4 严格模式

严格模式 strict 下会有以下特点:

  1. 对于分区表,用户不允许扫描所有分区。

  2. 使用了order by语句的查询,要求必须使用limit语句。

  3. 限制笛卡尔积的查询。

3.5 开启map端combiner

在不影响最终业务逻辑前提下,手动开启 set hive.map.aggr=true;

3.6 压缩

设置map端输出中间结果压缩,加速网络传输。

3.7 小文件进行合并

在Map执行前合并小文件,减少Map数,CombineHiveInputFormat 具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat没有对小文件合并功能。

3.8 其他

  1. Fetch抓取:指的是 Hive中对某些情况的查询可以不必使用MapReduce计算。

  2. 本地模式:Hive可以通过本地模式在单台机器上处理所有的任务。

  3. 数据分区:数据细化存储方便访问。

  4. JVM重用:JVM实例在同一个job中重新使用N次。

  5. 推测执行:根据一定的法则推测出拖后腿的任务,并为这样的任务启动一个备份任务。

  6. 并行执行:一个Hive查询被分解成多个阶段,阶段之间并非完全互相依赖的。

4 Hive 高频考点

4.1 数据倾斜

4.1.1 定义

数据分布不平衡,某些地方特别多,某些地方又特别少,导致的在处理数据的时候,有些很快就处理完了,而有些又迟迟未能处理完,导致整体任务最终迟迟无法完成,这种现象就是数据倾斜。

4.1.2 产生
  1. key的分布不均匀或者说某些key太集中

  2. 业务数据自身的特性,例如不同数据类型关联产生数据倾斜

  3. SQL语句导致的数据倾斜

4.1.3 解决
  1. 不影响最终业务逻辑前提下开启map端combiner。

  2. 开启数据倾斜时负载均衡。

  3. 手动抽查做好分区规则。

  4. 使用mapjoin,小表进内存 在Map端完成Reduce。

4.2 分区表和分桶表对比?

4.2.1 分区表
  1. 分区使用的是表外字段,需要指定字段类型

  2. 分区通过关键字 partitioned by(partition_name string)声明

  3. 分区划分粒度较粗

  4. 将数据按区域划分开,查询时不用扫描无关的数据,加快查询速度

4.2.2 分桶表

分桶逻辑:对分桶字段求哈希值,用哈希值与分桶的数量取余决定数据放到哪个桶里。

  1. 分桶使用的是表内字段,已经知道字段类型,不需要再指定。

  2. 分桶表通过关键字 clustered by(column_name) into … buckets声明

  3. 分桶是更细粒度的划分、管理数据,可以对表进行先分区再分桶的划分策略

  4. 优点在于用于数据取样时候能够起到优化加速的作用

4.3 动态分区

  1. 静态分区与动态分区的主要区别在于静态分区是手动指定,而动态分区是通过数据来进行判断。

  2. 静态分区的列是在编译时期,通过用户传递来决定的,动态分区只有在 SQL 执行时才能决定。

  3. 系统默认开启,非严格模式,动态分区最大值。

4.4 Hive 中视图跟索引

4.4.1 视图

视图是一种使用查询语句定义的虚拟表,是数据的一种逻辑结构,创建视图时不会把视图存储到磁盘上,定义视图的查询语句只有在执行视图的语句时才会被执行。视图是只读的,不能向视图中插入或是加载数据

4.4.2 Hive索引

Hive支持在表中建立索引。但是索引需要额外的存储空间,因此在创建索引时需要考虑索引的必要性。

Hive不支持直接使用 DROP TABLE 语句删除索引表。如果创建索引的表被删除了,则其对应的索引和索引表也会被删除;如果表的某个分区被删除了,则该分区对应的分区索引也会被删除。

4.5 Sort By、Order By、Distrbute By、Cluster By

  1. Sort By:分区内有序

  2. Order By:全局排序,只有一个Reducer

  3. Distrbute By:类似MR中Partition,进行分区,结合sort by使用

  4. Cluster By:当Distribute by和Sorts by字段相同时,可以使用Cluster by方式。Cluster by 还兼具 Sort by 的功能,但只能是升序排序。

4.6  内部表 跟外部表

4.6.1 内部表

如果Hive中没有特别指定,则默认创建的表都是管理表,也称内部表。由Hive负责管理表中的数据,管理表不共享数据。删除管理表时,会删除管理表中的数据和元数据信息。

4.6.2 外部表

当一份数据需要被共享时,可以创建一个外部表指向这份数据。删除该表并不会删除掉原始数据,删除的是表的元数据。

4.7 UDF 、UDAF、UDTF

  1. UDF :一进一出,类似 upper,trim

  2. UDAF:多进一出,聚集函数,类似 count、max、min。

  3. UDTF:一进多出,如 lateral view explore()

4.8 HQL 如何转变为MapReduce

  1. Antlr定义SQL语法规则,完成SQL词法,语法解析,SQL转化为 抽象语法树 AST Tree。

  2. 遍历AST Tree,抽象出查询的基本组成单元QueryBlock。

  3. 遍历QueryBlock,翻译为执行操作树OperatorTree。

  4. 逻辑层优化OperatorTree变换,合并不必要的ReduceSinkOperator,减少Shuffle数量。

  5. 遍历OperatorTree 翻译为MapReduce任务。

  6. 物理层优化器进行MapReduce任务变换,生成最终执行计划。

Hive 高频考点讲解相关推荐

  1. hive 时间转字符串_大数据面试杀招——Hive高频考点,还不会的进来挨打

    一.什么是Hive,为什么要用Hive,你是如何理解Hive? 面试官往往一上来就一个"灵魂三连问",很多没有提前准备好的小伙伴基本回答得都磕磕绊绊,效果不是很好.下面贴出菌哥的回 ...

  2. 大数据面试杀招——Spark高频考点,必知必会!

    前面两篇文章分别为大家介绍了大数据面试杀招 关于Hive 与 Hadoop 的内容,收到读者朋友们一致的好评和赞赏.嘿嘿,本篇文章我们就继续来研究,关于Spark的面试热点,又有哪些~ 一.你是怎么理 ...

  3. 看完了108份面试题,我为你总结出了这 10 个【Hive】高频考点(建议收藏)

    前言 之前听 CSDN 头牌博主 @沉默王二 说过一句话,我觉得十分在理:处在互联网时代,是一种幸福,因为各式各样的信息非常容易触达,如果掌握了信息筛选的能力,就真的是"运筹帷幄之中,决胜千 ...

  4. 双代号网络图节点编号原则_『干货』二级建造师考试高频考点 双代号网络图的详细解析...

    准备二级建造师考试的朋友们注意了,一年一度的二级建造师考试马上又要开始了,不管现在是不是已经开始备考,都要注意双代号网络图是二建考试中的一个高频考点,话说在管理科目中双代号网络图在2015-2018年 ...

  5. 秋招来袭,想学习Java进大厂的小伙伴,这7点武林秘籍一定要点开看看!(附一线互联网大厂MySQL面试高频考点)

    转眼间六月已经过了十天了.六月虽是盛夏,但秋招也不远了.提早做好准备才能在实战中游刃有余. 今天整理更新一篇Java学习分阶段路线攻略.希望能给大家一些启发,找到一条属于自己的学习线路. 本文为转载. ...

  6. 怎么判断有几个滴定突跃点_高中化学怎么学?先看近5年高考化学高频考点知识点分值分析...

    一.近5年全国卷高考化学考点分析 ●必考:必修一.必修二.选修四 ●选考:选修三.选修五任选一题 下面5幅图分别是每本书各章节内容占比,以期帮助同学们有重点地进行复习: ps:更值得一提的是,从201 ...

  7. 山西农信社计算机知识,山西人事考试网 山西农信社考试计算机知识高频考点(二)...

    山西人事考试网 山西农信社考试 山西人事考试网山西农信社考试 计算机知识高频考点(二) 山西人事考试网,为各位考生精心整理了2014山西农信社考试备考资料.希望为各位考生提供帮助,祝各位考生在山西农信 ...

  8. c++ map 修改value_干货 | 名企高频考点如何使用map统计字符串各个字符出现的次数...

    点击蓝字关注我哦 以下是本期干货视频视频后还附有文字版本哦▼<名企高频考点-如何使用map统计字符串各个字符出现的次数>▼ps:请在WiFi环境下打开,如果有钱任性请随意有某公司这样一道笔 ...

  9. 面试官问:能否模拟实现JS的new操作符(高频考点)

    可以点击上方的话题JS基础系列,查看往期文章 这篇文章写于2018年11月05日,new模拟实现,Object.create是面试高频考点,之前发布在掘金有近2万人阅读,现在发布到公众号声明原创. 1 ...

最新文章

  1. bootstrap modal 弹出效果
  2. 【查询】—Entity Framework实例详解
  3. 关于URL重写的一点心得
  4. [PHP] 使用 pcntl 库实现PHP多进程
  5. C语言常见单链表面试题(2)
  6. R开发(part6)--pryr包
  7. python装饰器作用和功能_Python装饰器原理与用法分析
  8. go的timer定时器实现
  9. ruby循环_Ruby循环
  10. jqgrid表格下拉搜索多选框优化—使用select下拉多选插件
  11. oracle in查询 一直等待,学习笔记:Oracle awr 分析解决inactive transaction branch等待事件...
  12. BZOJ 1878: [SDOI2009]HH的项链【莫队】
  13. java io 字符流操作工具类
  14. 关于win10专业版无法下载暴雪战网的解决方案
  15. 0基础怎么学习SEO?
  16. 万测试验机软件,万测关注检查井盖质量检测
  17. eclipse Build Automatically在哪里
  18. Accumulation Degree --- 换根dp
  19. 为什么去开发一个MLSQL
  20. qpython3手机版turtle_使用Python turtle画一片树林

热门文章

  1. Java非阻塞I/O模型之NIO说明
  2. centos7.9 配置nginx实现前后端分离
  3. 传真休眠怎么取消_C盘满了怎么办——系统瘦身
  4. 【动态规划、计算几何】最优三角剖分
  5. 解题报告:luogu P3469 [POI2008]BLO-Blockade(割点判定 + 思维计算)
  6. oracle enterprise linux 5.7,Red Hat Enterprise Linux 5.7 安装Oracle数据库
  7. C++ 对引用的深入理解
  8. 一口气搞懂《虚函数和纯虚函数》
  9. 模块化的 Windows 7
  10. C++ 11 创建和使用 shared_ptr