数据库非本地时 INSERT 查询极其慢

问题描述 投票:0回答:1

我正在将数据添加到 PythonAnywhere 上的

MySQL 8
数据库中。我通过使用
python 3.10
VSCode
中运行的
SSH Tunnel
脚本来执行此操作。当我添加数据时,添加 275 行大约需要 50 秒,json 格式的数据为 750kb,所以总数可能会比这个小一些。没有错误消息。

当我使用相同的脚本将相同的数据添加到本地计算机上的数据库时,需要 0.2 秒。在提交之间使用批量大小将总时间从 75 秒减少到 50 秒,但这是我得到的最好的时间。它适用于网络爬虫,当完整的东西运行时,它可能有几百到几千行要添加/删除,所以这样保留它是站不住脚的。由于性能如此糟糕,我一定是做错了什么,但我看不出它是什么。计时器围绕插入查询,它不包括 ssh 连接时间等。

这是怎么回事?

表列如下,目前正在使用索引:

"listingID int PRIMARY KEY AUTO_INCREMENT, types VARCHAR(11), town VARCHAR(255), postcode CHAR(5), price INT UNSIGNED, agent VARCHAR(50), ref VARCHAR(30), bedrooms SMALLINT UNSIGNED, rooms SMALLINT UNSIGNED, plot MEDIUMINT UNSIGNED, size MEDIUMINT UNSIGNED, link_url VARCHAR(1024), description VARCHAR(14000), photos TEXT, photos_hosted TEXT, gps POINT, id VARCHAR(80), types_original VARCHAR(30)"

添加数据的函数如下。正如我所说,它在本地 0.2 秒内完成,所以我不认为我在那里做了什么太糟糕的事情,即使它并不完美。

listings
是字典列表。使用字典进行插入的奇怪用途是因为我在 mysql.connector 中使用命名占位符,但由于访问数据库的另一个问题,我不得不切换到 MySQLdb,并且它不允许命名占位符。

def insert_data_to_table(cursor, table_name, columns_list, values_dict, gps_string):
    # Creates a string of csv %s placeholders for the values to be inserted
    placeholders = ", ".join(f"%s" for _ in values_dict.keys())

    # Creates a string of columns to be inserted
    columns = ", ".join(columns_list)

    # If GPS data is provided, insert specific string into query. Else build query without GPS sub string.
    if gps_string:
        insert_query = f"INSERT INTO {table_name} (gps, {columns}) VALUES ({gps_string}, {placeholders})"
    else:
        insert_query = f"INSERT INTO {table_name} ({columns}) VALUES ({placeholders})"

    cursor.execute(insert_query, tuple(values_dict.values()))

def add_listings(cursor, listings):
    print("Adding data...")
    counter = 0
    for listing in listings:
    # Committing every 50 rows rather than after each row reduces time by approx 33%, minimal differences 
     between 20, 50, 100 etc.
        if counter > 50:
            print("Commit", counter)
            db.commit()
            counter = 0
        columns_list = []

        values_dict = {key: None for key in listing if key != "gps"}

        if listing.get("gps") is None:
            gps_string = None
        elif isinstance(listing.get("gps"), list):
            gps_string = f"ST_GeomFromText('POINT({round(listing['gps'][0], 6)} {round(listing['gps'][1], 6)})', 4326)"

        for key in values_dict:
            if isinstance(listing.get(key), list):
                values_dict[key] = ":;:".join([str(x) for x in listing[key]])
            else:
                values_dict[key] = listing.get(key)
            columns_list.append(key)

        insert_data_to_table(cursor, table_name, columns_list, values_dict, gps_string)
        counter += 1
    db.commit()
python sql mysql pythonanywhere
1个回答
0
投票

您可以扩展您的解决方案。将数据文件上传到目标服务器,并在可能的情况下从 crontab 运行迁移。也许会更快。

© www.soinside.com 2019 - 2024. All rights reserved.