本文介绍如何通过Optimize和Vacuum命令优化表。

Optimize

  • Scala
    import io.delta.tables._
    
    val deltaTable = DeltaTable.forPath(spark, "/tmp/delta_table")
    
    deltaTable.optimizeExpr("date < '2019-11-11'", Seq("date", "id"))                       // 使用SQL字符串。
    
    import org.apache.spark.sql.functions._
    import spark.implicits._
    
    deltaTable.optimize(col("date < '2019-11-11'"), Seq(col("date"), col("id")))            // 使用SQL函数和隐式转换。
  • SQL
    OPTIMIZE delta_table [WHERE t.date < '2019-11-11'] [ZORDER BY t.date,t.id];

    deltaTable.optimize()不指定参数时,表示对全表进行优化。

    说明 从EMR-3.27.0版本开始支持ZOrder功能。

Vacuum

通过Optimize后,小文件会被合并为大文件,并且小文件被标记为墓碑文件。因为Delta有访问历史的功能,所以原有小文件不会被删除,当访问历史版本时,仍然需要读取小文件,影响优化表的执行效率。

Vacuum用于清理历史文件。如果墓碑文件涉及的数据过时很久,可以用Vacuum命令将其物理删除。默认情况下,墓碑文件只有经过一个安全期才能被删除,如果删除一个尚在安全期内的文件,将会抛出异常。

如果您要删除近期的墓碑文件,例如1天前的墓碑文件,可通过以下两种方式:
  • 设置合理的安全期参数(推荐):spark.databricks.delta.properties.defaults.deletedFileRetentionDurationinterval 1 day2 weeks365 days等。不支持设置MonthYear。这些参数为表的静态属性,无法通过命令行或者设置--conf来实现。其设置方法为:
    1. spark-default.conf中配置全局属性。
    2. 通过ALTER TABLE <tbl> SET PROPERTIES (key=value)更改此表属性。
  • 通过关闭安全期检查(不推荐):设置set spark.databricks.delta.retentionDurationCheck.enabled = flase关闭后,即可删除近期合并过的小文件。
注意
  • 不建议关闭安全期检查。
  • 不建议安全期设置过小。

    过小的安全期可能导致正在读取某一历史版本的作业失败。甚至导致当前执行作业产生的临时文件被清理掉,从而导致作业失败。

  • Scala
    import io.delta.tables._
    val deltaTable = DeltaTable.forPath(spark, pathToTable)
    
    deltaTable.vacuum()        // 物理删除超出安全期的墓碑文件。
    deltaTable.vacuum(100)     // 物理删除100小时前的墓碑文件。
  • SQL
    VACUUM table_name [RETAIN num HOURS] [DRY RUN]
    相关介绍如下:
    • 通过RETAIN子句指定删除超出设置时间间隔的墓碑文件。RETAIN num HOURS的默认值为spark.databricks.delta.properties.defaults.deletedFileRetentionDuration指定的值。
    • 如果指定了DRY RUN,被删除文件不会被实际删除。