Table history schema and operation metrics

The DESCRIBE HISTORY command returns 14 columns for Apache Iceberg and Delta Lake tables that describe the history of table operations. Use this reference to interpret each column.

For guidance on retrieving table history, querying earlier table versions, and restoring a table, see Work with table history.

History schema

The output of the history operation has the following columns.

Column Type Description
version long The table version generated by the operation.
timestamp timestamp When this version was committed.
userId string The ID of the user that ran the operation.
userName string The name of the user that ran the operation.
operation string The name of the operation.
operationParameters map The parameters of the operation (for example, predicates.) For OPTIMIZE operations, these parameters identify the type of operation. See Identify the type of OPTIMIZE operation.
job struct The details of the Lakeflow job that ran the operation. Populates only for commits written from a Lakeflow job. Otherwise, null.
notebook struct The details of the Databricks notebook from which the operation was run. Populates only for commits written from a Databricks notebook. Otherwise, null.
clusterId string The ID of the cluster on which the operation ran.
readVersion long The version of the table that was read to perform the write operation.
isolationLevel string The isolation level used for this operation.
isBlindAppend boolean Whether this operation appended data.
operationMetrics map The metrics of the operation (for example, number of rows and files modified.)
userMetadata string The user-defined commit metadata if it was specified.
+-------+-------------------+------+--------+---------+--------------------+----+--------+---------+-----------+-----------------+-------------+--------------------+
|version|          timestamp|userId|userName|operation| operationParameters| job|notebook|clusterId|readVersion|   isolationLevel|isBlindAppend|    operationMetrics|
+-------+-------------------+------+--------+---------+--------------------+----+--------+---------+-----------+-----------------+-------------+--------------------+
|      5|2019-07-29 14:07:47|   ###|     ###|   DELETE|[predicate -> ["(...|null|     ###|      ###|          4|WriteSerializable|        false|[numTotalRows -> ...|
|      4|2019-07-29 14:07:41|   ###|     ###|   UPDATE|[predicate -> (id...|null|     ###|      ###|          3|WriteSerializable|        false|[numTotalRows -> ...|
|      3|2019-07-29 14:07:29|   ###|     ###|   DELETE|[predicate -> ["(...|null|     ###|      ###|          2|WriteSerializable|        false|[numTotalRows -> ...|
|      2|2019-07-29 14:06:56|   ###|     ###|   UPDATE|[predicate -> (id...|null|     ###|      ###|          1|WriteSerializable|        false|[numTotalRows -> ...|
|      1|2019-07-29 14:04:31|   ###|     ###|   DELETE|[predicate -> ["(...|null|     ###|      ###|          0|WriteSerializable|        false|[numTotalRows -> ...|
|      0|2019-07-29 14:01:40|   ###|     ###|    WRITE|[mode -> ErrorIfE...|null|     ###|      ###|       null|WriteSerializable|         true|[numFiles -> 2, n...|
+-------+-------------------+------+--------+---------+--------------------+----+--------+---------+-----------+-----------------+-------------+--------------------+

Note

Understanding partitionBy in operation parameters

The partitionBy field in table history is only meaningful for CREATE and OVERWRITE operations that define or change a table's partition schema.

For append operations to existing tables (APPEND, INSERT, UPDATE, DELETE, MERGE), this field might show an empty array [] or partition columns depending on the write method used (.save() vs .saveAsTable()).

This inconsistency is expected behavior and doesn't affect how data is written to partitions. You shouldn't use it to validate append operations.

Example

Consider a table partitioned by the date column. When you create the table, partitionBy is populated:

df.write.format("delta") \
  .partitionBy("date") \
  .saveAsTable("sales_data")

The CREATE operation in history shows:

operationParameters: {
  "mode": "ErrorIfExists",
  "partitionBy": "[\"date\"]"
}

When you append data to this table, partitionBy shows an empty array:

new_df.write.format("delta") \
  .mode("append") \
  .saveAsTable("sales_data")

The APPEND operation shows:

operationParameters: {
  "mode": "Append",
  "partitionBy": "[]"
}

The empty partitionBy value is expected. The data is still written to the correct partitions based on the table's existing partition schema. Note that .save() to a path might show partition columns in this field, but this difference is an implementation detail and doesn't affect write behavior.

Operation metrics

The history operation returns a collection of operation metrics in the operationMetrics column map.

The following tables list the map key definitions by operation.

WRITE, CREATE TABLE AS SELECT, REPLACE TABLE AS SELECT, COPY INTO

The following metrics are available for these operations:

Metric name Description
numFiles The number of files written.
numOutputBytes The size in bytes of the written contents.
numOutputRows The number of rows written.

STREAMING UPDATE

The following metrics are available for this operation:

Metric name Description
numAddedFiles The number of files added.
numRemovedFiles The number of files removed.
numOutputRows The number of rows written.
numOutputBytes The size of the write in bytes.

DELETE

The following metrics are available for this operation:

Metric name Description
numAddedFiles The number of files added. Not provided when partitions of the table are deleted.
numRemovedFiles The number of files removed.
numDeletedRows The number of rows removed. Not provided when partitions of the table are deleted.
numCopiedRows The number of rows copied in the process of deleting files.
executionTimeMs The time taken to execute the entire operation.
scanTimeMs The time taken to scan the files for matches.
rewriteTimeMs The time taken to rewrite the matched files.

TRUNCATE

The following metrics are available for this operation:

Metric name Description
numRemovedFiles The number of files removed.
executionTimeMs The time taken to execute the entire operation.

MERGE

The following metrics are available for this operation:

Metric name Description
numSourceRows The number of rows in the source DataFrame.
numTargetRowsInserted The number of rows inserted into the target table.
numTargetRowsUpdated The number of rows updated in the target table.
numTargetRowsDeleted The number of rows deleted in the target table.
numTargetRowsCopied The number of target rows copied.
numOutputRows The total number of rows written out.
numTargetFilesAdded The number of files added to the sink (target).
numTargetFilesRemoved The number of files removed from the sink (target).
executionTimeMs The time taken to execute the entire operation.
scanTimeMs The time taken to scan the files for matches.
rewriteTimeMs The time taken to rewrite the matched files.

UPDATE

The following metrics are available for this operation:

Metric name Description
numAddedFiles The number of files added.
numRemovedFiles The number of files removed.
numUpdatedRows The number of rows updated.
numCopiedRows The number of rows just copied over in the process of updating files.
executionTimeMs The time taken to execute the entire operation.
scanTimeMs The time taken to scan the files for matches.
rewriteTimeMs The time taken to rewrite the matched files.

FSCK

The following metrics are available for this operation:

Metric name Description
numRemovedFiles The number of files removed.

CONVERT

The following metrics are available for this operation:

Metric name Description
numConvertedFiles The number of Parquet files that have been converted.

OPTIMIZE

The following metrics are available for this operation:

Metric name Description
numAddedFiles The number of files added.
numRemovedFiles The number of files optimized.
numAddedBytes The number of bytes added after the table was optimized.
numRemovedBytes The number of bytes removed.
minFileSize The size of the smallest file after the table was optimized.
p25FileSize The size of the 25th percentile file after the table was optimized.
p50FileSize The median file size after the table was optimized.
p75FileSize The size of the 75th percentile file after the table was optimized.
maxFileSize The size of the largest file after the table was optimized.

CLONE

The following metrics are available for this operation:

Metric name Description
sourceTableSize The size in bytes of the source table at the version that's cloned.
sourceNumOfFiles The number of files in the source table at the version that's cloned.
numRemovedFiles The number of files removed from the target table if a previous table was replaced.
removedFilesSize The total size in bytes of the files removed from the target table if a previous table was replaced.
numCopiedFiles The number of files that were copied over to the new location. 0 for shallow clones.
copiedFilesSize The total size in bytes of the files that were copied over to the new location. 0 for shallow clones.

RESTORE

The following metrics are available for this operation:

Metric name Description
tableSizeAfterRestore The table size in bytes after restore.
numOfFilesAfterRestore The number of files in the table after restore.
numRemovedFiles The number of files removed by the restore operation.
numRestoredFiles The number of files that were added as a result of the restore.
removedFilesSize The size in bytes of files removed by the restore.
restoredFilesSize The size in bytes of files added by the restore.

VACUUM

The following metrics are available for this operation:

Metric name Description
numDeletedFiles The number of deleted files.
numVacuumedDirectories The number of vacuumed directories.
numFilesToDelete The number of files to delete.