我正在分区拼花地板中编写一个大表(大约 1.2b 行(,我正在使用状态(如美国州(作为分区键。问题是存在大量空状态值。此表通常按状态查询,因此具有空状态的大分区不是问题,但我在更有效地生成表时遇到了麻烦。
我尝试使用非 null 状态创建表,然后插入 null,但据我所知,所有 null 值仍然只是放在一个大分区中,因此发送给一个工作人员。
如果有一种方法可以插入到特定分区中,那就太好了。就像我的例子一样,写入非空状态,然后将剩余的记录插入到 state=null 或 hive_default_partition 中,其方式仍会跨集群并行。
尝试使用自动分区写入非空数据,然后重新分区空数据并单独写入,例如:
df.where($”state”.isNotNull).write.partitionBy($”state”).parquet(“my_output_dir”)
df.where($”state”.isNull).repartition(100).write.parquet(“my_output_dir/state=__HIVE_DEFAULT_PARTITION__”)
使用 SQL API,可以使用重新分区提示(在 Spark 2.4 中引入(来完成相同的操作:
spark-sql> describe skew_test;
id bigint NULL
dt date NULL
state string NULL
# Partition Information
# col_name data_type comment
state string NULL
Time taken: 0.035 seconds, Fetched 6 row(s)
spark-sql> CREATE TABLE `skew_test2` (`id` BIGINT, `dt` DATE, `state` STRING)
> USING parquet
> OPTIONS (
> `serialization.format` '1'
> )
> PARTITIONED BY (state);
Time taken: 0.06 seconds
spark-sql> insert into table skew_test2 select * from skew_test where state is not null;
Time taken: 1.208 seconds
spark-sql> insert into table skew_test2 select /*+ REPARTITION(100) */ * from skew_test where state is null;
Time taken: 1.39 seconds
您应该看到 Spark 为最终语句创建的 100 个任务,并且您的 state=__HIVE_DEFAULT_PARTITION__
目录应包含 100 个镶木地板文件。有关 Spark-SQL 提示的详细信息,请查看 https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-hint-framework.html#specifying-query-hints