Sql server 如何将大型Spark数据帧(1.2 GB 14M行)写入MSSQL服务器tbl?我目前的解决方案大约需要10个小时

Sql server 如何将大型Spark数据帧(1.2 GB 14M行)写入MSSQL服务器tbl?我目前的解决方案大约需要10个小时,sql-server,apache-spark,apache-spark-sql,azure-databricks,sql-server-2019,Sql Server,Apache Spark,Apache Spark Sql,Azure Databricks,Sql Server 2019,问题: 1.2 GB(1400万条记录)存储在apache spark数据帧中。计算耗时不到1分钟,但写入MSSQL服务器表(无索引)的时间超过10小时硬件:(1-VM 8-VCPU,64 GB内存,SSD)。问题:以下几点尝试都没有成功,你有什么好的想法、建议或者简单的建议可以帮助你吗?谢谢 def FUNC_A1(df):  start = time.time()   jdbc_url = f"jdbc:sqlserver://{config.get('mydb',

问题: 1.2 GB(1400万条记录)存储在apache spark数据帧中。计算耗时不到1分钟,但写入MSSQL服务器表(无索引)的时间超过10小时硬件:(1-VM 8-VCPU,64 GB内存,SSD)。问题:以下几点尝试都没有成功,你有什么好的想法、建议或者简单的建议可以帮助你吗?谢谢

def FUNC_A1(df):  
    start = time.time()
    jdbc_url = f"jdbc:sqlserver://{config.get('mydb',
    'host')}:1434;database={config.get('mydb', 'database')}"
    df.select("F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9")\ 
      .write.format("jdbc").mode("overwrite") \
      .option("driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver")\
      .option("url", jdbc_url) \
      .option("dbtable", "dbo.tblAFS") \
      .option("user", config.get('mydb', 'username'))\
      .option("password", config.get('mydb', 'password'))\
      .save()
前面的代码创建了表,但在尝试插入记录时失败,并生成以下错误消息

选项#1(此代码需要9到10个小时才能完成,它正在将实际结果(数据帧)写入表中


选项2花费的时间与选项1相同_

已经考虑了以下想法,但尚未在显著缩短处理时间的情况下实施。
  • 在这种情况下不应使用rdd.collect(),因为它将收集所有 数据作为一个数组存储在驱动程序中,这是获取数据的最简单方法 记忆
  • 还不应将rdd.coalesce(1).saveAsTextFile()用作 上游阶段的并行性将丢失,无法在一个平台上执行 单节点,从中存储数据
  • coalesce(1,shuffle=true).saveAsTextFile()是最简单的 选项,因为它将保持上游任务的并行处理和 然后只对一个节点执行洗牌 (rdd.repartition(1).saveAsTextFile()是一个确切的同义词)
  • 下面提供的rdd.saveAsSingleTextFile()还允许 使用特定名称将rdd存储在单个文件中,同时保留 coalesce(1,shuffle)的并行性= true)。保存ASTEXTFILE()

  • 有两种方法。首先,删除索引、主键和外键,使用spark作业在该表中插入日期。作业完成后,重新创建反索引、主键和外键

    或者,您可以创建一个新表,比如说,表temp与原始表具有相同的结构,但没有任何约束。在表temp中插入数据,并使用表temp更新原始表


    使用第一种方法,几天前我在40分钟内插入了一个Oracle DB 500-800百万行。

    有两种方法。首先,删除索引、主键和外键,使用spark作业在该表中插入日期。作业完成后,重新创建反索引、主键和外键

    或者,您可以创建一个新表,比如说,表temp与原始表具有相同的结构,但没有任何约束。在表temp中插入数据,并使用表temp更新原始表


    使用第一种方法,几天前,我在40分钟内插入了一个Oracle DB 500-800百万行。

    您声明的数字相当于大约每秒插入389行,这太低了。如果您在虚拟机上,可能您的邻居吵闹?SQL Server是否在主机上设置了内存保留?它应该……您声明的数字是相当于大约每秒插入389行,这太低了。如果您在虚拟机上,可能有吵闹的邻居?SQL Server是否在主机上设置了内存保留?它应该……不要出于明显的原因删除PK或FK(另外,您可能会将PK与群集键混淆)这取决于DB中的目标表是空表还是已经包含数据。如果目标表已经包含日期,正确的方法是使用临时表。在SQL数据库中插入数据不受群集键的影响。它受Spark executors建立的连接数、该表使用的约束数的影响根据批量大小,“在SQL数据库中插入数据不受群集密钥的影响”-这是不正确的。为什么“在SQL数据库中插入数据不受群集密钥的影响”是不正确的?不要出于明显的原因删除PK或FK(另外,您可能会将PK与群集密钥混淆)这取决于DB中的目标表是空表还是已经包含数据。如果目标表已经包含日期,正确的方法是使用临时表。在SQL数据库中插入数据不受群集键的影响。它受Spark executors建立的连接数、该表使用的约束数的影响根据批量大小,“在SQL数据库中插入数据不受群集键的影响”-这是不正确的。为什么“在SQL数据库中插入数据不受群集键的影响”是不正确的?
         # Execute insert into tblAFS for each row in dataframe
         # Using fast execute
    
         start = time.time()
         df = df.select("F1", "F2", "F3", "F4", "F5",
              "F6", "F7", "F8", "F9").na.fill(0)
         conn = pyodbc.connect(shared.get_odbcconn(config))
         cursor = conn.cursor()
         cursor.fast_executemany = True
         collected = df.rdd.toLocalIterator()
         counter = 1
         for row in collected:
            cursor.execute("""
                   INSERT INTO dbo.tblAFS 
                   ([F1],[F2],[F3],[F4],[F5],[F6],[F7],[F8],[F9])
                   VALUES (?,?,?,?,?,?,?,?,?)""",
                     row["F1"], row["F2"], row["F3"], row["F4"], row["F5"],
                     row["F6"], row["F7"], row["F8"], row["F9"])
            counter = counter + 1
        conn.commit()
        conn.close()
    
    def FUNC_C1(df):
        # 1. Create csv file for each F2 partition
        # 2. Bulk insert all files generated in table tblAFS
    
        start = time.time()
        file_path = config.get('action', 'stats_results')
        df = df.select("F1", "F2", "F3", "F4", "F5",
                       "F6", "F7", "F8", "F70").na.fill(0)
    
        df.write.mode("overwrite").options(header=True).csv(file_path)
        conn = pyodbc.connect(shared.get_odbcconn(config))
        cursor = conn.cursor()
        cursor.fast_executemany = True
        files = glob(f"{file_path}/*.csv")
        counter = 1
        for file in files:
            cursor.execute(f"BULK INSERT dbo.tblAFS FROM '{getcwd()}/{file}' 
                 WITH (FORMAT = 'CSV', FIRSTROW = 2)")
            counter = counter+1
        conn.commit()
        conn.close()