今天有客户咨询到我们,他们利用spark sql查询简单的sql:
select * from datetable limit 5; //假设表名是datetable
结果报错内存溢出:
根据常理判断,简单的 select * limit 不会造成内存溢出的。因此,我们用hive原生sql查询,发现不存在这个问题。
经过分析,发现被查询的表数据量特别大,整个表有1000多亿行数据。一般这种海量数据大型数据表,往往是做了多重分区的。
经过查看,发现被查询的数据表是双重分区表(也就是有两个分区字段)。dt是第一个分区字段,表示天; hour是第二个分区字段,表示小时。数据表存储在HDFS的目录结构也是:
/${hive-warehouse}/dbname/tablename/dt=xxx/hour=xxx/files
根据之前使用spark sql的经验、以及逛社区查找的信息,最终找到原因如下:
因为 datetable 这个表是一个双重分区表,即使进行 select * limit 也至少会进行第一重分区的完整数据扫描。因此,对于双重分区表,需要加上双重分区条件(或者至少加上第一重分区条件),然后再进行 select * limit 查询。比如:
select * from datetable where dt='2018-11-14' and hour='07' limit 5;
或者至少把第一重分区条件加上:
select * from datetable where dt='2018-11-14' limit 5;
不能直接用 :
select * from datetable limit 5;
这种语句spark sql至少会扫描一个完整的第一重分区的数据,当数据量很大的时候,因此往往会出现内存不足。因为datetable有1000亿行数据,单个的第一重分区的数据量往往也是超过TB级别的。因此,如果全量扫描TB级别数据到有限数量的excutor内存里面去,肯定会出现内存不足。
1、首先我们直接用spark sql查询:
select * from datetable limit 5;
从日志可以查看出excutor在疯狂地扫描HDFS的文件:
而且这些被扫描的HDFS文件,确实属于表的某个第一重分区的目录。日志证明刚才的推断是正确的。
2、加上第一重分区条件:
select * from datetable where dt='2018-11-14' limit 5;
很快就返回结果。
3、加上第一重和第二重分区条件:
select * from datetable where dt='2018-11-14' and hour='07' limit 5;
毫秒级就出结果。
因此,经过验证,上述分析完全正确。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。