Создание таблиц в MySQL на основе имен столбцов в другой таблице - PullRequest
0 голосов
/ 31 мая 2018

У меня есть таблица с ~ 133M строк и 16 столбцов.Я хочу создать 14 таблиц в другой базе данных на том же сервере для каждого из столбцов 3-16 (столбцы 1 и 2 - `id` и `timestamp`, которые также будут в последних 14 таблицах, но не будут иметь своих собственныхтаблица), где каждая таблица будет иметь имя исходного столбца.Возможно ли это сделать исключительно с помощью сценария SQL?Мне кажется логичным, что это было бы предпочтительным и самым быстрым способом сделать это.

В настоящее время у меня есть скрипт Python, который «работает», анализируя дамп CSV исходной таблицы (тестирование с 50 строками), создание новых таблиц и добавление связанных значений, но это очень медленно (я оценил почти 1 год для переноса всех 133M строк, что явно неприемлемо).Я впервые использую SQL в любом качестве, и я уверен, что мой код может быть ускорен, но я не уверен, как из-за моего незнакомого с SQL.Большая строковая команда SQL в середине была скопирована из некоторого другого кода в нашей кодовой базе.Я пытался использовать транзакции, как показано ниже, но это не оказало существенного влияния на скорость.

import re
import mysql.connector
import time

# option flags
debug = False  # prints out information during runtime
timing = True  # times the execution time of the program

# save start time for timing. won't be used later if timing is false
start_time = time.time()

# open file for reading
path = 'test_vaisala_sql.csv'
file = open(path, 'r')

# read in column values
column_str = file.readline().strip()
columns = re.split(',vaisala_|,', column_str)  # parse columns with regex to remove commas and vasiala_
if debug:
    print(columns)

# open connection to MySQL server
cnx = mysql.connector.connect(user='root', password='<redacted>',
                              host='127.0.0.1',
                              database='measurements')
cursor = cnx.cursor()

# create the table in the MySQL database if it doesn't already exist
for i in range(2, len(columns)):
    table_name = 'vaisala2_' + columns[i]
    sql_command = "CREATE TABLE IF NOT EXISTS " + \
                  table_name + "(`id` BIGINT(20) NOT NULL AUTO_INCREMENT, " \
                               "`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, " \
                               "`milliseconds` BIGINT(20) NOT NULL DEFAULT '0', " \
                               "`value` varchar(255) DEFAULT NULL, " \
                               "PRIMARY KEY (`id`), " \
                               "UNIQUE KEY `milliseconds` (`milliseconds`)" \
                               "COMMENT 'Eliminates duplicate millisecond values', " \
                               "KEY `timestamp` (`timestamp`)) " \
                               "ENGINE=InnoDB DEFAULT CHARSET=utf8;"

    if debug:
        print("Creating table", table_name, "in database")

    cursor.execute(sql_command)

# read in rest of lines in CSV file
for line in file.readlines():
    cursor.execute("START TRANSACTION;")
    line = line.strip()
    values = re.split(',"|",|,', line)  # regex split along commas, or commas and quotes
    if debug:
        print(values)

    # iterate of each data column. Starts at 2 to eliminate `id` and `timestamp`
    for i in range(2, len(columns)):
        table_name = "vaisala2_" + columns[i]
        timestamp = values[1]

        # translate timestamp back to epoch time
        try:
            pattern = '%Y-%m-%d %H:%M:%S'
            epoch = int(time.mktime(time.strptime(timestamp, pattern)))
            milliseconds = epoch * 1000  # convert seconds to ms
        except ValueError:  # errors default to 0
            milliseconds = 0

        value = values[i]

        # generate SQL command to insert data into destination table
        sql_command = "INSERT IGNORE INTO {} VALUES (NULL,'{}',{},'{}');".format(table_name, timestamp,
                                                                                 milliseconds, value)
        if debug:
            print(sql_command)

        cursor.execute(sql_command)
cnx.commit()  # commits changes in destination MySQL server

# print total execution time
if timing:
    print("Completed in %s seconds" % (time.time() - start_time))

Это не должно быть невероятно оптимизировано;Это вполне приемлемо, если машина должна работать в течение нескольких дней, чтобы сделать это.Но 1 год это слишком долго.

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

При использовании сценариев для связи с базами данных вы хотите минимизировать количество отправляемых сообщений, поскольку каждое сообщение создает дополнительную задержку по времени выполнения.В настоящее время выглядит так, как будто вы отправляете (по вашему приближению) 133 миллиона сообщений, и, следовательно, замедляете свой сценарий в 133 миллиона раз.Простая оптимизация состояла бы в том, чтобы проанализировать вашу электронную таблицу и разбить данные на таблицы (либо в памяти, либо сохранить их на диск), и только затем отправлять данные в новую БД.

Как вы уже намекнули, это намного быстреенаписать сценарий SQL для перераспределения данных.

0 голосов
/ 31 мая 2018

Вы можете создать таблицу из SELECT, например:

CREATE TABLE <other database name>.<column name>
             AS
             SELECT <column name>
                    FROM <original database name>.<table name>;

(Замените <...> вашими фактическими именами объектов или добавьте в него другие столбцы или предложение WHERE или ...)

Это также вставит данные из запроса в новую таблицу.И это, вероятно, самый быстрый способ.

Вы можете использовать динамический SQL и информацию из каталога (а именно information_schema.columns), чтобы создавать операторы CREATE или создавать их вручную, что раздражает.но приемлемо для 14 столбцов, я думаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...