SQL 死锁 Python 数据插入

SQL Deadlock with Python Data Insert

我目前正在尝试使用 python 构建一个数据库接口来存储股票数据。此数据采用元组列表的形式,每个元素由“日期、开盘价、最高价、最低价、收盘价、成交量”组成。date 表示 UNIX 时间戳,并且必须与数据库。下面是典型处理输出的示例 (company_stock):

 [(1489780560, 'NYSE:F', 12.5, 12.505, 12.49, 12.495, 567726),
 (1489780620, 'NYSE:F', 12.495, 12.5, 12.48, 12.48, 832487),
 (1489780680, 'NYSE:F', 12.485, 12.49, 12.47, 12.475, 649818),
 (1489780740, 'NYSE:F', 12.475, 12.48, 12.47, 12.47, 700579),
 (1489780800, 'NYSE:F', 12.47, 12.48, 12.47, 12.48, 567798)]

我正在使用 pymysql 包将此列表插入本地 MySQL 数据库(版本 5.5)。当代码 运行 完成并插入值时,数据库将在达到约 250k 行后崩溃 - 或者更确切地说停止。由于相关 这是股票数据处理功能的导出部分,大约每 20 秒调用一次并插入大约 400 个值。

# SQL Export
def tosql(company_stock, ticker, interval, amount_period, period):
    try:
        conn = pymysql.connect(host = "localhost", user = "root", 
                               passwd = "pw", db = "db", charset = "utf8",
                               autocommit = True, 
                               cursorclass = pymysql.cursors.DictCursor)
        cur = conn.cursor()

        # To temp table
        query = "INSERT INTO stockdata_import "
        query += "(date, tickersymbol, open, high, low, close, volume)"
        query += "VALUES (%s, %s, %s, %s, %s, %s, %s)"
        cur.executemany(query, company_stock)

        # Duplicate Check with temp table and existing database storage
        query = "INSERT INTO stockdata (date, tickersymbol, open, high, low, close, volume) "
        query += "SELECT i.date, i.tickersymbol, i.open, i.high, i.low, "
        query += "i.close, i.volume FROM stockdata_import i "
        query += "WHERE NOT EXISTS(SELECT dv.date, dv.tickersymbol FROM "
        query += "stockdata dv WHERE dv.date = i.date "
        query += "AND dv.tickersymbol = i.tickersymbol)"
        cur.execute(query)

        print(": ".join([datetime.now().strftime("%d.%m.%Y %H:%M:%S"), 
                         "Data stored in Vault. Ticker", str(ticker),
                         "Interval", str(interval), 
                         "Last", str(amount_period), str(period)]))
    finally:
        # Clear temp import table and close connection
        query = "DELETE from stockdata_import"
        cur.execute(query)
        cur.close()
        conn.close()

我怀疑随着数据库的增长检查已经存在的值花费的时间太长,最终由于检查 [=55= 的唯一性时 tables (?) 的锁定而崩溃] 组合。因为我希望这个数据库增长得相当快(每周大约 100 万行),所以似乎需要一个不同的解决方案来确保只有一个 date/ticker 对。这是导入 table 的 SQL CREATE 语句(与之比较的真实 table 看起来是一样的):

CREATE TABLE stockdata_import (id_stock_imp BIGINT(12) NOT NULL AUTO_INCREMENT,
             date INT(10),
             tickersymbol VARCHAR(16),
             open FLOAT(12,4),
             high FLOAT(12,4),
             low FLOAT(12,4),
             close FLOAT(12,4),
             volume INT(12),
             crawled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
             PRIMARY KEY(id_stock_imp));

我已经研究过为 date/tickersymbol 对设置约束并处理 python 中即将发生的异常,但到目前为止我的研究表明这将是均匀的更慢加上我什至不确定这是否适用于 pymysql 游标函数 executemany(query, data).

的批量插入

上下文信息:

问题:

  1. 如何优化查询或更改存储 table 以确保给定 date/ticker 组合的唯一性?
  2. 这就是问题所在,还是我在这里没有看到其他问题?
  3. 也欢迎任何进一步的建议。

如果您想确保数据的唯一性,只需在相关的dateticker 字段上添加一个unique 索引即可。唯一索引防止插入重复值,因此插入前无需检查数据是否存在。

既然不想插入重复数据,就用insert ignore代替plain insert来抑制重复插入错误。根据受影响的行数,您仍然可以检测并记录重复插入。