首页 > 解决方案 > 为什么 sqlalchemy 似乎自发地提交某些查询而忽略其他查询?

问题描述

我有一个古怪的 GCP 云功能,通过利用网站接受数字升序的“id”参数,在某种高级别的非智能网站抓取。

主文件

def upsert(db, i, x, y):
    with db.connect() as cursor:
        cursor.execute(f"REPLACE INTO TABLE_NAME (i, x, y) VALUES (i, \"{x}\", \"{y}\"")

def main(data, context):
    db = sqlalchemy.connect(...)

    for i in range(0, 100):
        soup = BeautifulSoup(f"websiteimscraping.com/id={i}")
        if soup is not valid:
            continue

        x = soup.find_all(...)
        y = soup.find_all(...)

        upsert(db, i, x, y)

在此示例中,我知道一个事实,即大多数(如果不是全部)id 的 0 到 99 都是有效的 + 唯一的,当云功能完成时,我应该在数据库中拥有非常相似数量的行。

为了验证我在 MySQL 中有 100 行,我进入调试模式并计算表达式:

list(cursor.execute("SELECT * FROM TABLE_NAME"))

我得到了我期望的 20% 的行,没有任何顺序。像 (7, 8, 9, 10, 13, 44, 45, 46, 47, 48, 49, 50, 51, 86)

我做了一些打印语句,以确保没有触发我的边缘情况(这将导致跳过无效的 id),实际上,代码中没有,我通过在调试模式下单步执行并查看所有 id 发送到upsert步骤。

我认为需要澄清的重要一点是,每次保存到数据库的行都不是随机确定的->每次都没有插入/更新相同的行。

我正在做的一个核心假设是,如果没有插入的行存在数据问题导致REPLACE语句出现问题,sqlalchemy 会为我引发异常。sqlalchemy 在整个函数中没有引发任何异常。

是否有任何与 sqlalchemy无关的数据可能导致无法插入行?

我已经尝试在数据中寻找已插入的行的模式,以尝试衡量某种数据(不)一致性或模式(这似乎是更可能的嫌疑人),但没有找到任何模式。

我希望将代码提供给我以进行复制更简单,但我很确定没有人想设置自己的 mysql 实例来尝试这一点 - 如果你愿意,我很乐意提供实际代码,你可以自己试试。

标签: pythonmysqlgoogle-cloud-platformbeautifulsoupsqlalchemy

解决方案


我已经执行了你的代码,并设法重现了你的场景,遇到了同样的问题,似乎只插入了一些行。

问题是您使用的是 REPLACE 语句。如MySQL 文档中所述,REPLACE 语句的工作方式与 INSERT 操作完全相同,如果PRIMARY KEY已经存在,则替换所述行而不是使查询失败。

根据您的共享代码,您似乎正在使用该字段codePRIMARY KEY但您正在检查该字段id作为插入网页的指示符。发生的情况是多行具有相同的code,因此每次插入前一行时都会删除前一行。

我已经解决了您的问题,只需将字段id设置PRIMARY KEYcode. 一旦你改变了它(记得删除原始表),你可以再次运行你的代码,你会看到没有丢失id的 s。您可以使用以下方法进行验证:

SELECT id FROM CLASSES_MASTER;

顺便说一句,现在您已经插入了所有数据,您可以使用以下命令检查重复代码的数量:

SELECT code, COUNT(*) FROM CLASSES_MASTER GROUP BY code;

推荐阅读