hivesql常见的与不常见的日期格式转换 (持续更新)

本文记录了在Hive中处理日期格式转换的各种方法,包括将非标准格式如'03/16/yyyy HH:mm:ss'转换为标准格式,以及处理不同长度的时间戳。还探讨了从毫秒时间戳到日期的转换,如除以1000或字符串切割,并提到了可能遇到的问题和解决方案。目前内容更新至20200306,后续会补充更多日期转换示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

12/31/2015 00:00:00
12/31/2015 00:00:00
1/4/2016 00:00:00
1/4/2016 00:00:00

故事起源于某日接手了 ↑ 这种日期格式的数据 mm/dd/yyyy HH:mm:ss ,

需要将数据放进hive里,肯定得转成标准格式呀。baidu了很久没找到所需函数,只找到了类似的 :

16/Mar/2017:12:25:01 +0800 转成正常格式(yyyy-MM-dd hh:mm:ss)

select from_unixtime(to_unix_timestamp('16/Mar/2017:12:25:01 +0800', 'dd/MMM/yyy:HH:mm:ss Z'))

所以本文将持续记录各种 常用/不常用 的各类日期转换函数 。(后期视情况可能会加入自定义函数udf)   

[ps:当前更新日期20200306]

 

首先,mm/dd/yyyy HH:mm:ss 这种格式,You can try this:

select from_unixtime(unix_timestamp('9/26/2011 00:00:00' ,'MM/dd/yyyy HH:mm:ss'), 'yyyy-MM-dd HH:mm:ss');

 

timstamp毫秒时间戳(13位) 格式化 :

毫秒时间戳是13位的,所以可以选择两种方法:1.除以1000,再格式化

select from_unixtime(cast(updata_time/1000 as bigint), 'yyyy-MM-dd') date
from access_log;

2.字符串切割掉后3位,再格式化

select from_unixtime(cast(substring(updata_time, 1, 10) as bigint),'yyyy-MM-dd HH') date
from access_log;

因为updata_time为bigint格式,需要转化为秒,结果会变成double格式,所以需要用cast转换

from_unixtime(cast(updata_time/1000 as bigint)) as updata_time

hive里不填写格式会默认转化为标准时间格式,所以也可以写成自己所需格式:

from_unixtime(cast(updata_time/1000 as bigint),'yyyy-MM-dd HH:mm:ss') as updata_time

 

///描述一种比较坑的情况:

时间戳转时间:数据中我们希望看到的是 yyyy-MM-dd HH:mm:ss,然而实际传来的数据可能是1234567890,或者1234567890’ 

from_unixtime(cast(SUBSTR(updata_time, 1, 10) as bigint) , 'yyyy-MM-dd HH:mm:ss')

这行代码即可,槽点在于输入是10位的 bigint or double (有时候时间戳是按毫秒级,所以会有13位):

1.如果输入 updata_time 是 int or double 类型:直接 updata_time/1000 即可;

2.如果输入是string,则: cast(SUBSTR(updata_time, 1, 10) as bigint 

 

 

 

 

时间格式转换:

from_unixtime(unix_timestamp('2018-11-05','yyyy-MM-dd'),'yyyy/MM/dd')

date_format('2015-04-08 10:10:01', 'yyyy-MM')

concat(substr('2018-09-05',1,4),substr('2018-09-05',6,2),substr('2018-09-05',9,2))

(时间仓促,有时间了再补上这三种方法的说明)

 

 

常用日期格式转换part1:

固定日期转换成时间戳
select unix_timestamp('2016-08-16','yyyy-MM-dd') --1471276800
select unix_timestamp('20160816','yyyyMMdd') --1471276800
select unix_timestamp('2016-08-16T10:02:41Z', "yyyy-MM-dd'T'HH:mm:ss'Z'") --1471312961

16/Mar/2017:12:25:01 +0800 转成正常格式(yyyy-MM-dd hh:mm:ss)
select from_unixtime(to_unix_timestamp('16/Mar/2017:12:25:01 +0800', 'dd/MMM/yyy:HH:mm:ss Z'))

时间戳转换程固定日期
select from_unixtime(1471276800,'yyyy-MM-dd') --2016-08-16
select from_unixtime(1471276800,'yyyyMMdd') --20160816
select from_unixtime(1471312961) --    2016-08-16 10:02:41
select from_unixtime( unix_timestamp('20160816','yyyyMMdd'),'yyyy-MM-dd')  --2016-08-16
select date_format('2016-08-16','yyyyMMdd') --20160816

返回日期时间字段中的日期部分
select to_date('2016-08-16 10:03:01') --2016-08-16
取当前时间
select from_unixtime(unix_timestamp(),'yyyy-MM-dd HH:mm:ss')
select from_unixtime(unix_timestamp(),'yyyy-MM-dd') 
返回日期中的年
select year('2016-08-16 10:03:01') --2016
返回日期中的月
select month('2016-08-16 10:03:01') --8
返回日期中的日
select day('2016-08-16 10:03:01') --16
返回日期中的时
select hour('2016-08-16 10:03:01') --10
返回日期中的分
select minute('2016-08-16 10:03:01') --3
返回日期中的秒
select second('2016-08-16 10:03:01') --1

返回日期在当前的周数
select weekofyear('2016-08-16 10:03:01') --33

返回结束日期减去开始日期的天数
select datediff('2016-08-16','2016-08-11') 

返回开始日期startdate增加days天后的日期
select date_add('2016-08-16',10)

返回开始日期startdate减少days天后的日期
select date_sub('2016-08-16',10)

返回当天三种方式
SELECT CURRENT_DATE;
--2017-06-15
SELECT CURRENT_TIMESTAMP;--返回时分秒
--2017-06-15 19:54:44
SELECT from_unixtime(unix_timestamp());
--2017-06-15 19:55:04
返回当前时间戳
Select current_timestamp--2018-06-18 10:37:53.278

返回当月的第一天
select trunc('2016-08-16','MM') --2016-08-01
返回当年的第一天
select trunc('2016-08-16','YEAR') --2016-01-01

 

part2:

--把 20180123 转换成 2018-01-23,可以使用:
select from_unixtime(unix_timestamp('${p_date}','yyyymmdd'),'yyyy-mm-dd') from table;

1.日期函数UNIX时间戳转日期函数
from_unixtime语法:from_unixtime(bigint unixtime[, stringformat]) 
返回值: string 说明: 转化UNIX时间戳(从1970-01-0100:00:00 UTC到指定时间的秒数)到当前时区的时间格式
举例:
select from_unixtime(1323308943,'yyyyMMdd') from dual;
20111208

2.获取当前UNIX时间戳函数: unix_timestamp语法:   unix_timestamp() 
返回值: bigint 
<think>嗯...用户这次明确要HiveSQL的性能优化技巧和最佳实践,看来是遇到实际性能问题了。上次对话中用户对SQL优化很关注,这次是专业领域的深度提问。用户可能正在处理大规模数据,遇到了执行效率瓶颈,需要可落地的解决方案。考虑到Hive常用于TB/PB级数据仓库,优化确实很关键。从技术角度看,Hive优化需要分层处理:首先是数据存储优化,这是基础;然后是查询编写技巧,这直接决定执行效率;最后是配置调优。用户可能更关注前两者,因为配置调优往往需要管理员权限。存储优化方面要重点讲分区和分桶,这是Hive的核心理念。注意到用户习惯看代码示例,所有优化点都需要配SQL范例说明。另外得提醒BloomFilter这类新特性,很多老用户可能还知道。查询优化要强调数据倾斜处理,这是生产环境最常见痛点。需要给出具体解决方案,比如用distributeby处理倾斜的实例。MapJoin优化也要重点讲,小表关联的场景太普遍了。配置参数部分反而用太多,列举最有价值的几个即可。最后务必加上执行计划分析技巧,授人以渔很重要。用户既然问最佳实践,应该是有长期优化需求的。对了,补充说明里要强调数据格式选择,ORC/Parquet的压缩比差异很关键,现在企业都在降本增效。所有建议必须标注适用场景,避免用户误用。</think> 好的,Hive SQL 性能优化是一个实践性很强的话题,涉及存储、计算、资源配置和查询编写等多个层面。以下是一些关键的优化技巧和最佳实践,适用于处理大规模数据集: ### 一、 数据存储格式优化 1. **分区 (Partitioning):** * **技巧:** 将数据按逻辑列(如日期`dt`、地区`region`)划分存储。 * **优化点:** 查询时只扫描相关分区数据,大幅减少I/O。 * **示例:** ```sql -- 创建分区表 CREATE TABLE logs ( user_id BIGINT, url STRING, ip STRING ) PARTITIONED BY (dt STRING); -- 查询特定日期的数据 SELECT * FROM logs WHERE dt = '2023-10-27'; ``` * **最佳实践:** 选择高频过滤的列作为分区键,避免创建过多小分区(小文件问题)。 2. **分桶 (Bucketing):** * **技巧:** 基于表某一列的哈希值,将数据均匀分布到固定数量的存储桶中。 * **优化点:** 提高`JOIN`和`GROUP BY`效率,特别是等值连接/聚合。 * **示例:** ```sql -- 创建分桶表 CREATE TABLE users_bucketed ( user_id BIGINT, name STRING, ... ) CLUSTERED BY (user_id) INTO 32 BUCKETS; -- 分桶表Join更高效 SELECT a.*, b.* FROM orders a JOIN users_bucketed b ON a.user_id = b.user_id; ``` * **最佳实践:** 对于经常关联的大表定义相同数量和字段的分桶,启用`hive.optimize.bucketmapjoin`或`hive.optimize.bucketmapjoin.sortedmerge`选项效果更佳。 3. **选择合适的文件格式:** * **推荐:** **ORC** (Optimized Row Columnar) 或 **Parquet** (列式存储)。 * **优化点:** * **列裁剪 (Column Pruning):** 只读取查询涉及的列。 * **高效压缩:** ORC和Parquet内置高压缩比算法。 * **谓词下推 (Predicate Pushdown):** 在读取文件时尽早应用过滤条件(`WHERE`中的部分过滤)。 * **索引:** ORC提供了轻量级内部索引(如布隆过滤器)。 * **最佳实践:** 优先选择ORC或Parquet作为生产环境数据存储格式。 4. **启用ORC布隆过滤器 (Bloom Filter):** * **技巧:** 在表/列级别为常用`WHERE`条件的列创建布隆过滤器。 * **优化点:** 快速判断数据块中是否包含特定键值,显著减少必要的IO读取。 * **示例:** ```sql CREATE TABLE my_orc_table ( id INT, name STRING, ... ) STORED AS ORC tblproperties ( "orc.bloom.filter.columns" = "id", "orc.bloom.filter.fpp" = "0.05" -- 期望假阳性概率 ); -- 针对id查询会利用布隆过滤器 SELECT * FROM my_orc_table WHERE id = 12345; ``` 5. **压缩数据:** * **技巧:** 配置表属性使用压缩算法(如Snappy, Zlib, LZO),特别是对于文本格式。 * **优化点:** 减少磁盘I/O和网络传输开销。 * **最佳实践:** ORC/Parquet文件格式本身有压缩,通常无需额外配置。 ### 二、 查询编写优化 6. **`SELECT`语句只取所需列:** * **技巧:** **避免**使用`SELECT *`。 * **优化点:** 启用列裁剪后,能显著减少读取和处理的数据量。对于列存格式效果极佳。 * **最佳实践:** 明确列出所有需要的列名。 7. **尽早过滤数据 (`WHERE` / `HAVING`):** * **技巧:** 在数据流向`JOIN`或`GROUP BY`之前,尽早应用过滤条件。 * **优化点:** 减少后续处理阶段的数据量。谓词下推对此有很大帮助。 * **最佳实践:** ```sql -- 推荐:先过滤表A SELECT ... FROM ( SELECT * FROM big_table_a WHERE condition) a JOIN big_table_b b ON a.key = b.key; -- 避免:在JOIN后过滤表A SELECT ... FROM big_table_a a JOIN big_table_b b ON a.key = b.key WHERE a.condition; -- 此时a可能已通过JOIN膨胀了 ``` 8. **优化`JOIN`操作:** * **Map-side JOIN (`MapJoin`):** * **技巧:** 对小表(能完全加载进内存的表)使用MapJoin。将小表广播到所有Map任务。 * **优化点:** 避免Reduce阶段开销和网络传输。 * **触发:** ```sql -- 方法1:设置自动转换小表 SET hive.auto.convert.join = true; SET hive.mapjoin.smalltable.filesize = 25000000; -- 设置小表阈值(默认约25MB) -- 方法2:显式提示 SELECT /*+ MAPJOIN(small_table) */ ... FROM big_table JOIN small_table ... ``` * **处理数据倾斜:** * **问题:** `JOIN`或`GROUP BY`时某些Key值特别多,导致一两个Reduce任务执行时间长。 * **解决方法:** * **设置并行任务数:** `SET mapreduce.job.reduces = N;` (N一般设为集群Reduce槽位总数的倍数)。 * **增加处理倾斜Key的Reducer数:** ```sql SET hive.groupby.skewindata=true; -- 针对GROUP BY倾斜 ``` * **手动分离倾斜Key:** ```sql -- 将倾斜Key单独处理 (假设id=0是倾斜Key) SELECT ... FROM ( SELECT ... FROM A JOIN B WHERE A.id != 0 UNION ALL SELECT ... FROM A JOIN B WHERE A.id = 0 AND B.id = 0) tmp; ``` * **使用`DISTRIBUTE BY` + `RAND()`打散:** ```sql -- 对Join键添加随机后缀 SELECT ... FROM ( SELECT id, ..., CAST(RAND() * 10 AS INT) AS salt FROM skewed_table ) a JOIN large_table b ON CONCAT(a.id, '_', a.salt) = b.id; -- 或者直接分布随机后缀 SELECT ... FROM skewed_table a JOIN large_table b ON a.id = b.id DISTRIBUTE BY RAND() SORT BY ...; -- 确保打散均匀 ``` 9. **优化聚合操作 (`GROUP BY`):** * **开启Map端部分聚合 (`HASHAGG`):** ```sql SET hive.map.aggr = true; -- 默认开启,在Map端做预聚合,减少Reduce端数据量 ``` * **使用`GROUPING SETS`, `ROLLUP`, `CUBE`代替多个查询:** 减少扫描次数。注意可能会增加Reducer负载。 * **处理`GROUP BY`倾斜:** 方法同`JOIN`倾斜处理(见第8点)。 10. **使用`SORT BY`代替`ORDER BY`:** * `SORT BY`:在每个Reduce任务内部排序,输出局部有序结果(全局一定有序)。 * `ORDER BY`:保证全局有序,但会将所有数据汇流到单个Reducer进行排序,极易成为瓶颈。 * **最佳实践:** 除非必须全局排序,否则优先使用`SORT BY`(通常`DISTRIBUTE BY`配合)。如需全局有序且数据量极大,考虑分治或其他架构。 11. **使用`LIMIT`进行抽样:** * **技巧:** 在开发调试时,对表查询加`LIMIT`减少数据量加速响应。 * **注意:** `LIMIT`在子查询中的位置会影响优化器行为,有时需配合`ORDER BY NULL`避免排序。 12. **分析`EXPLAIN`输出:** * **技巧:** 在查询语句前添加`EXPLAIN`(或`EXPLAIN EXTENDED`, `EXPLAIN DEPENDENCY`, `EXPLAIN AUTHORIZATION`获取更详细信息)。 * **优化点:** 理解Hive为查询生成的实际执行计划(MR或Tez),识别潜在的瓶颈或优化点(如未使用分区、MapJoin未被触发等)。分析执行计划是性能调优的基础。 ### 三、 计算引擎资源配置 (视引擎而定 - MR / Tez / Spark) 13. **选择合适的计算引擎:** * **Tez:** 推荐。基于DAG执行,避免重复读写HDFS,任务提交更快,资源申请更灵活(如动态容器复用)。通常性能优于MR。 * **Spark:** 另一种高性能DAG引擎,内存计算能力强。 * **MR:** 经典引擎,稳定性高,但调度开销相对大。 * **设置:** `SET hive.execution.engine=tez|mr|spark;` 14. **合理设置Mapper/Reducer数量:** * **目标:** 让每个Mapper处理合适的块大小(约等于HDFS块大小,如128MB),Reducer数量避免过大(导致小文件)或过小(导致倾斜或OOM)。 * **Mapper数:** 基本由输入文件数量和大小决定。调整`mapreduce.input.fileinputformat.split.minsize`/`maxsize`间接控制。 * **Reducer数:** * `mapreduce.job.reduces = N;` (直接指定)。 * Hive估算:`hive.exec.reducers.bytes.per.reducer` (默认约256MB)。 * 最大Reducers数:`hive.exec.reducers.max` (默认1009)。 * **最佳实践:** 优先让Hive自动估算,出现数据倾斜时再考虑手动干预。 15. **调整资源参数 (根据集群规模调整):** * Map/Reduce任务内存: ```sql SET mapreduce.map.memory.mb = 4096; -- 单个Map任务容器内存申请量 SET mapreduce.reduce.memory.mb = 8192; -- 单个Reduce任务容器内存申请量 SET mapreduce.map.java.opts = -Xmx3072m; -- Map任务JVM堆内存 (应小于总内存, 预留堆外开销) SET mapreduce.reduce.java.opts = -Xmx6144m; -- Reduce任务JVM堆内存 ``` * **最佳实践:** 监控任务是否因内存足失败(查看GC日志或任务错误),逐步增加。避免设置过大导致资源碎片或OOM风险更高。充分利用YARN的调度能力。 ### 四、 元数据管理统计分析 16. **收集表统计信息:** * **技巧:** 使用`ANALYZE TABLE`命令收集关键统计信息。 * **优化点:** Hive CBO (Cost-Based Optimizer) 依赖这些信息生成更优的执行计划(如选择Join顺序,估算中间结果大小)。 * **示例:** ```sql ANALYZE TABLE my_table PARTITION(dt='2023-10-27') COMPUTE STATISTICS; -- 基础统计(行数、文件数) ANALYZE TABLE my_table PARTITION(dt='2023-10-27') COMPUTE STATISTICS FOR COLUMNS column1, column2; -- 列统计(NDV, min/max等) ``` * **最佳实践:** 定期或在数据发生重大变更后运行。对分区表收集分区级别的统计。 17. **使用`Vectorization` (向量化):** * **技巧:** 启用向量化查询执行。 * **优化点:** 一次处理一批数据(向量),减少虚函数调用开销,利用现代CPU的SIMD指令。 * **设置:** ```sql SET hive.vectorized.execution.enabled = true; -- 启用向量化 SET hive.vectorized.execution.reduce.enabled = true; -- 启用Reduce端向量化(Hive较新版本才支持完善) ``` * **注意:** 主要对计算密集型操作(如过滤、聚合)效果好。ORC文件格式支持良好。需检查执行计划是否真正应用了向量化。 ### 五、 其他实践小技巧 * **优化小文件:** * **问题:** HDFS上大量小文件增加NameNode压力,降低MR/Tez处理效率。 * **解决方法:** * 设置`hive.merge.mapfiles` / `hive.merge.mapredfiles` / `hive.merge.tezfiles` = true (在任务结束时合并小文件)。 * 设置`hive.merge.size.per.task` / `hive.merge.smallfiles.avgsize`定义合并大小阈值。 * 使用`INSERT OVERWRITE ...`语句重写表/分区时自动合并。 * 使用`hive --service concat`等工具手动合并。 * **使用中间表:** 将复杂查询拆分成多个步骤,使用中间表存储中间结果。方便调试、复用和优化各阶段。 * **避免多趟`COUNT(DISTINCT)`:** ```sql -- 低效:多次扫描数据 SELECT COUNT(DISTINCT col1), COUNT(DISTINCT col2) FROM table; -- 改进:使用单个查询计算多个distinct (Hive 2.0+支持一定程度优化,但复杂时仍需考虑改写为GROUP BY + COUNT或同子查询) -- 或 -- 利用GROUP BY + CASE WHEN SELECT COUNT(DISTINCT CASE WHEN ... THEN col1 ELSE NULL END), COUNT(DISTINCT CASE WHEN ... THEN col2 ELSE NULL END) FROM table; ``` **总结:** Hive SQL性能优化是系统工程,需要: 1. **精心设计数据模型:** 利用分区、分桶、高效格式。 2. **编写高效查询:** 遵循列裁剪、谓词下推、优化JOIN/GROUP BY等原则。 3. **配置合适资源:** 匹配计算引擎资源需求。 4. **启用统计优化器:** 支持CBO做出最优决策。 5. **监控分析:** 使用`EXPLAIN`理解计划,监控任务执行和资源使用情况。 持续应用这些技巧并结合具体场景实践,能显著提升Hive处理大数据的效率。 *** ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值