Почему запись из Spark в Vertica DB занимает больше времени, чем запись из Spark в MySQL?

В конечном счете, я хочу получить данные из базы данных Vertica в Spark, обучить модель машинного обучения, сделать прогнозы и сохранить эти прогнозы в другой базе данных Vertica.

Текущая проблема заключается в выявлении узкого места в последней части потока: сохранении значений в БД Vertica из Spark. Для хранения 63 тыс. строк данных в базе данных Vertica требуется около 38 минут. Для сравнения, когда я переношу те же данные из Spark в базу данных MySQL, это занимает 10 секунд.

Не знаю, почему такая огромная разница.

У меня есть классы VerticaContext и MySQLContext для соединений Vertica и MySQL соответственно. Оба класса используют 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)

Между этими двумя классами нет никакой разницы, кроме записи в другую целевую базу данных. Я не понимаю, почему существует огромная разница во времени, необходимом для сохранения таблиц. Это из-за внутренней разницы в оборудовании между двумя разными базами данных?


person OfLettersAndNumbers    schedule 19.04.2016    source источник
comment
Возможно, это связано с тем, что Vertica является столбцовой базой данных?   -  person OfLettersAndNumbers    schedule 19.04.2016
comment
Spark выполняет одиночные INSERT?   -  person Kermit    schedule 19.04.2016
comment
В вашем вопросе слишком мало деталей. Возможно, ваша база данных Vertica не оптимизирована для ручных вставок, которые вы выполняете через JDBC. Вам нужно будет поговорить с вашим администратором баз данных.   -  person mustaccio    schedule 19.04.2016
comment
На стороне приложения вы можете попробовать вставлять потоковые вставки, как описано здесь   -  person mustaccio    schedule 19.04.2016
comment
@mustaccio, спасибо за ссылку. Вы знаете, есть ли эквивалент этого Python?   -  person OfLettersAndNumbers    schedule 20.04.2016
comment
Не уверен, что вы подразумеваете под эквивалентом Python; поскольку вы используете JDBC, настройка свойств JDBC не должна вызывать особых проблем, не так ли?   -  person mustaccio    schedule 20.04.2016
comment
@mustaccio в предоставленной вами ссылке есть код, написанный на java. Ссылаясь на комментарий, который вы оба сделали о вставках, похоже, что я выполняю вставки через JDBC из-за времени записи в Vertica DB. По этой ссылке: vertica-forums.com/viewtopic.php?t=124 похоже, что ВСТАВКИ занимают очень много времени, и мне нужно искать альтернативу КОПИРОВАНИЮ.   -  person OfLettersAndNumbers    schedule 20.04.2016
comment
Кто-нибудь из вас знает, есть ли способ изменить соединение JDBC, чтобы Vertica воспринимала запись как КОПИЮ?   -  person OfLettersAndNumbers    schedule 21.04.2016


Ответы (1)


Я придумал альтернативное решение. Прежде чем углубиться, я объясню, что я обнаружил и почему я думаю, что сохранение в Vertica DB происходит медленно.

  • Журнал Vertica (ищите файл «vertica.log» на вашем компьютере Vertica) содержит все последние журналы, связанные с чтением/записью из и в базы данных Vertica. Выполнив команду записи, я обнаружил, что это, по сути, создание операторов INSERT в базе данных Vertica.
  • Операторы INSERT (без директивы "DIRECT") выполняются медленно, потому что они записываются в WOS (ОЗУ), а не в ROS (диск). Я не знаю точных деталей, почему это так. Записи выдавали отдельные операторы INSERT
  • Медленные вставки — известная проблема. У меня были проблемы с поиском этой информации, но я наконец нашел несколько ссылок, подтверждающих это. Я размещаю их здесь для потомков: http://www.vertica-forums.com/viewtopic.php?t=267, http://vertica-forums.com/viewtopic.php?t=124

Мое решение:

Существует документация, в которой говорится команда COPY (с ключевым словом "DIRECT") является наиболее эффективным способом загрузки больших объемов данных в базу данных. Поскольку я искал решение для Python, я использовал пакет от Uber, который позволил мне установить соединение с БД Vertica и отправка команд Vertica для выполнения.

Я хочу использовать эффективность команды COPY, но данные находятся где-то за пределами кластера Vertica. Мне нужно отправить данные из моего кластера Spark в Vertica DB. К счастью, есть способ сделать это из HDFS (см. здесь). Я решил преобразовать фрейм данных в файл csv и сохранить его в HDFS. Затем я отправил команду COPY в базу данных Vertica, чтобы получить файл из 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
person OfLettersAndNumbers    schedule 25.04.2016
comment
Проблема в том, что он выполняет несколько insert...values, что очень неэффективно в Vertica. DIRECT, с которым вам нужно быть осторожным, если вы выполняете много транзакций с одной и той же таблицей за короткое время, поскольку каждая из них создает контейнер ROS. Однако использование COPY правильно. Кроме того, если ваши данные находятся в вашем фрейме данных, вы можете использовать метод копирования vertica_python и передавать данные таким образом вместо использования SOURCE... вы бы использовали FROM STDIN. - person woot; 29.04.2016