使用 "Insert or Ignore" 语句加速 Python executemany

Speed up Python executemany with "Insert or Ignore"-Statement

我是 pyodbc 的新手,运行 遇到 executemany 需要相当长的时间的问题。在对脚本进行基准测试时,将 962 行插入 table 大约需要 15 分钟。如果可能的话,我想加快这个查询的速度。

我运行以下脚本:

cursor = conn.cursor()
parsed_json = get_parsed_json_Event_Log()
print(f'Gathering data from API found {len(parsed_json)} entries')

cursor.fast_executemany=True
cursor.executemany(f"""
                        IF NOT EXISTS (SELECT 1 FROM {schema_name}.{table_name} WHERE id = ?)
                        INSERT INTO {schema_name}.{table_name}
                        SELECT  ?,
                                ?,
                                DATEADD(s, ?, '19700101 02:00:00:000'),
                                ?,
                                ?,
                                DATEADD(s, ?, '19700101 02:00:00:000'),
                                ?,
                                ?,
                                ?,
                                ?,
                                ?,
                                ?;""", parsed_json)

我正在使用 python 3.8.6 和 Azure SQL 服务器。解析后的 JSON 采用指定的序列格式,由 pyodbc 文档建议。 DATEADD 函数中的施法日期信息以全局秒数提供。

我试图实现 INSERT OR IGNORE INTO 语句,我知道这在 SQLite 中是可能的。不幸的是,我无法为 Azure SQL 服务器想出一个实现,因此必须默认为 IF NOT EXISTS 语句。

如果有人能帮助我加快脚本或改进语句以加快执行速度,那就太棒了。

我多次尝试加快查询速度并收集了一些见解,希望与可能遇到相同问题的每个人分享:

要点:

  1. 使用 Azure SQL 服务器时,始终尝试使用 INSERT INTO ... VALUES (...) 语句而不是 INSERT INTO ... SELECT ...,因为它的执行速度提高了大约 350%(针对所描述的问题和使用的语法进行基准测试时).
    • 我使用 INSERT INTO ... SELECT ... 的主要原因是因为特定的 DATEADD() Cast,因为如果不在 Azure SQL 服务器中明确声明变量就无法做到这一点。
  2. 如果您将提供的时间转换为 python datetime,则可以跳过给定示例中的 DATEADD()。如果您选择此选项,请确保在将数据插入 SQL Table 时不要使用文字字符串。除了@Charlieface 指出的不良做法外,PYODBC 在使用字符串文字输入时没有针对该数据类型的内置逻辑(这里的序列输入结构没有问题)
  3. IF NOT EXISTS声明真的很贵。如果可能,尽量省略它。如果您依赖于保留 table 历史记录,一个简单的解决方法是创建第二个新创建的 table,然后从那个 table 插入到未找到匹配项的原始位置。在这里您可以依赖于您的本地 SQL 实现而不是 PYODBC 实现。这种方式是迄今为止最快的。

不同的设计选择带来了以下性能改进:

  • INSERT INTO ... SELECT ... 对比 INSERT INTO ... VALUES (...):350%
  • 利用第二个 table 和原生 SQL 支持:560%