Azure Databricks 到 Azure SQL DW:长文本列

Posted

技术标签:

【中文标题】Azure Databricks 到 Azure SQL DW:长文本列【英文标题】:Azure Databricks to Azure SQL DW: Long text columns 【发布时间】:2020-06-16 16:52:23 【问题描述】:

我想从 Azure Databricks 笔记本环境填充 Azure SQL DW。我正在使用带有 pyspark 的内置连接器:

sdf.write \
  .format("com.databricks.spark.sqldw") \
  .option("forwardSparkAzureStorageCredentials", "true") \
  .option("dbTable", "test_table") \
  .option("url", url) \
  .option("tempDir", temp_dir) \
  .save()

这很好用,但是当我包含一个内容足够长的字符串列时会出错。我收到以下错误:

Py4JJavaError:调用 o1252.save 时出错。 : com.databricks.spark.sqldw.SqlDWSideException: SQL DW 无法执行连接器生成的 JDBC 查询。

基础 SQLException(s): - com.microsoft.sqlserver.jdbc.SQLServerException:HdfsBridge::recordReaderFillBuffer - 填充记录读取器缓冲区时遇到意外错误:HadoopSqlException:字符串或二进制数据将被截断。 [错误代码 = 107090] [SQLState = S0001]

据我了解,这是因为默认字符串类型是 NVARCHAR(256)。可以配置 (reference),但最大 NVARCHAR 长度为 4k 个字符。我的字符串偶尔会达到 10k 个字符。 因此,我很好奇如何将某些列导出为文本/长文本。

如果在创建表后只执行preActions,我猜以下方法会起作用。它不是,因此它失败了。

sdf.write \
  .format("com.databricks.spark.sqldw") \
  .option("forwardSparkAzureStorageCredentials", "true") \
  .option("dbTable", "test_table") \
  .option("url", url) \
  .option("tempDir", temp_dir) \
  .option("preActions", "ALTER TABLE test_table ALTER COLUMN value NVARCHAR(MAX);") \
  .save()

另外,postActions 是在插入数据后执行的,因此也会失败。

有什么想法吗?

【问题讨论】:

【参考方案1】:

我遇到了类似的问题,并且能够使用以下选项解决它:

.option("maxStrLength",4000)

因此,在您的示例中,这将是:

sdf.write \
  .format("com.databricks.spark.sqldw") \
  .option("forwardSparkAzureStorageCredentials", "true") \
  .option("dbTable", "test_table") \
  .option("maxStrLength",4000)\
  .option("url", url) \
  .option("tempDir", temp_dir) \
  .save()

这是documented here:

"Spark 中的 StringType 映射到 Azure Synapse 中的 NVARCHAR(maxStrLength) 类型。您可以使用 maxStrLength 为 Azure 中名为 dbTable 的表中的所有 NVARCHAR(maxStrLength) 类型列设置字符串长度突触。”

如果您的字符串超过 4k,那么您应该:

使用 NVARCHAR(MAX) 预定义表列,然后以追加模式写入表。在这种情况下,您不能使用默认的列存储索引,因此请使用 HEAP 或设置正确的索引。惰性堆是:

CREATE TABLE example.table
(
    NormalColumn NVARCHAR(256),
    LongColumn NVARCHAR(4000),
    VeryLongColumn NVARCHAR(MAX)
) 
WITH (HEAP)

然后你可以像往常一样写它,没有 maxStrLength 选项。这也意味着您不会过度指定所有其他字符串列。

其他选项是:

    使用 split 将 1 列转换为多个字符串列。 另存为镶木地板,然后从突触内部加载

【讨论】:

其实在大多数情况下VARCHAR(4000) 会比NVARCHAR(4000) 好,只是主题不同。

以上是关于Azure Databricks 到 Azure SQL DW:长文本列的主要内容,如果未能解决你的问题,请参考以下文章

使用 azure databricks 读取 azure databricks 日志 json 文件

使用 /mnt/ 将数据从 Azure Blob 存储读取到 Azure Databricks

作业终止后如何将生成的文件从 Azure Databricks 导出到 Azure DevOps?

从 Azure Databricks 笔记本登录到 Azure ML 工作区

Databricks:将数据框合并到 Azure 突触表中

将数据存储到 PySpark (Azure - DataBricks) 中的数据库非常慢