为什么从Spark写入Vertica DB比从Spark写入MySQL需要更长的时间?

时间:2016-04-19 17:39:45

标签: python mysql apache-spark vertica

最终,我想从Vertica数据库中获取数据到Spark,训练机器学习模型,进行预测,并将这些预测存储到另一个Vertica数据库中。

当前的问题是确定流程最后部分的瓶颈:在Spark中存储Vertica DB中的值。在Vertica DB中存储63k行数据大约需要38分钟。相比之下,当我将相同的数据从Spark传输到 MySQL数据库时,需要 10秒

我不知道为什么差异如此巨大。

我分别为Vertica和MySQL连接提供了名为VerticaContext和MySQLContext的类。两个类都使用SQLContext来使用jdbc格式读取条目。

df = self._sqlContext.read.format('jdbc').options(url=self._jdbcURL, dbtable=subquery).load()

使用jdbc编写。

df.write.jdbc(self._jdbcURL, table_name, save_mode)

除了写入不同的目标数据库之外,这两个类之间没有区别。我很困惑为什么保存表格所需的时间差别很大。是因为两个不同数据库之间硬件的固有差异吗?

1 个答案:

答案 0 :(得分:1)

我想出了另一种解决方案。在我深入研究之前,我将解释我发现的内容以及为什么我认为对Vertica DB的保存速度很慢。

  • Vertica日志(在Vertica计算机上搜索文件“vertica.log”)包含与Vertica DB的读取/写入相关的所有最新日志。运行write命令后,我发现这实际上是在Vertica DB中创建INSERT语句。
  • INSERT语句(没有“DIRECT”指令)很慢,因为它们被写入WOS(RAM)而不是ROS(磁盘)。我不知道为什么会这样的确切细节。写入发布了单独的INSERT语句
  • 慢插入是一个已知问题。我很难找到这些信息,但我终于找到了一些支持它的链接。我将它们放在这里供后人使用:http://www.vertica-forums.com/viewtopic.php?t=267http://vertica-forums.com/viewtopic.php?t=124

我的解决方案:

documentation表示COPY命令(带有“DIRECT”关键字)是将大量数据加载到数据库的最有效方法。由于我正在寻找python解决方案,我使用Uber的vertica-python package,它允许我与Vertica DB建立连接并发送Vertica命令来执行。

我想利用COPY命令的效率,但数据位于Vertica群集之外的某个位置。我需要将Spark集群中的数据发送到Vertica DB。幸运的是,有一种方法可以从HDFS中做到这一点(见here)。我决定将数据帧转换为csv文件并将其保存在HDFS上。然后我将COPY命令发送到Vertica DB以从HDFS获取文件。

我的代码在下面(假设我有一个存储pyspark数据帧的变量。让我们称之为'df'):

    import vertica_python as VertPy

    df.toPandas().to_csv(hdfs_table_absolute_filepath, header=False, index=False)
    conn_info = {
        'host': ['your-host-here']
        'port': [port #],
        'user': ['username'],
        'password': ['password'],
        'database': ['database']
    }

    conn = VertPy.connect(**conn_info)
    cur = conn.cursor()

    copy_command = create_copy_command(table_name, hdfs_table_relative_filepath)
    cursor.execute(copy_command)

    def create_copy_command(table_name, table_filepath):
        copy_command = "COPY " + table_name + " SOURCE Hdfs(url='http://hadoop:50070/webhdfs/v1" + table_filepath + "', username='root') DELIMITER ',' DIRECT ABORT ON ERROR"
        return copy_command