【发布时间】:2016-07-05 22:36:26
【问题描述】:
我编写了一个 python 程序,它使用 pyodbc 与 Microsoft Access 数据库进行交互。该数据库包含一个包含井测量值的表格(约 630 万个)。
该程序的基本工作流程是获取化学品清单。然后对于每种化学品,它将使用一个选择查询来查找表中包含该化学品数据的每一口井。对于每个孔,它将使用另一个选择查询来获取一个数据集,其中包含化学孔的所有测量值。
一旦有了这个数据集,它就会计算一些关于它的统计数据,用于为数据集所针对的化学品和孔对创建一个新行。然后将这些新行中的每一行输出到一个新的数据库表中。
请注意,我正在使用 python 的多处理包以允许程序使用更多的 cpu 容量。该程序始终有一个消费者进程,该进程将数据从队列中取出,并将其插入到与输入数据库不同的新数据库中。然后程序有可变数量的生产者进程,它们从队列中获取化学品,处理它们,然后将数据添加到输出队列中。
当我在很长的化学品清单上运行程序时,有时会出错:
Starting: 01027
Failed on 01027 when selecting wells for chemical.
Failed. Wells processed: 371693
Traceback (most recent call last):
File "C:\Users\jrutledge\Desktop\well_trend_processor_python_2016\python_processor\well_trends.py", line 230, in read_data_sets_into_queue
raise e
对于 96 种化学品的列表,这种情况至少发生一次(有时更多),但不会发生在 10 种或更少的情况下,不确定界限在哪里。此错误消息的预期原因似乎是运行占用太多内存的查询,但这似乎不是这里的结果。一个原因是,它错误的化学物质在尝试之间不一致。此外,如果我运行包含失败化学品的较小化学品列表,那么它们的处理不会出错。
当我为化学品选择孔时,问题似乎正在发生:
# Find each well that has samples of this chemical
wells_cursor = measurement_db_chemical.cursor()
sql_string = """SELECT DISTINCT {0}.Well_ID, PSCODE, STAID, Status
FROM {0}
LEFT JOIN {1}
ON {0}.Well_ID = {1}.Well_ID
WHERE STORE_NUM = ?""".format(
well_records_table_name, well_sites_table_name)
try:
wells_cursor.execute(sql_string, chemical.STORE_NUM)
# Close db connection if error, outer try will close connection
except Exception, e:
print ('Process {}: Failed on {} when selecting wells for chemical.'.format(process_number, chemical.STORE_NUM))
raise e
尽管如前所述,此 SQL 查询执行时没有问题的频率远高于导致错误的频率,因此 SQL 中似乎没有错误。但是,这是程序进行的最密集的查询,因此它会超出资源是有道理的。
如果我删除程序的插入部分,此问题仍然存在。通过这种方式,它会做所有它通常会做的事情,但是在计算完统计信息后,它不会将它们插入到新表中。
我认为这可能是由于与数据库的连接打开时间过长,并且不知何故它正在积累垃圾内存或其他东西。这导致我让 python 程序为每种化学品打开一个到数据库的新连接,然后在处理完该化学品后关闭它。但是,问题仍然存在。
值得注意的是,无论我如何运行它,总内存使用率都不会超过 60%,所以我认为这不是问题。
此外,数据库的大小小于 800 mb,这与 MS Access 数据库的 2 GB 大小限制相去甚远。
我只用一个进程运行了这个程序,它工作正常。这使我认为,尽管任何选择查询对于 ODBC 驱动程序来说可能不会太耗费资源,但同时执行多个非常昂贵的查询可能会导致驱动程序达到其资源限制。我现在已经修改了程序并在数据库中执行任何 SQL 查询时添加了 python RLocks,这样一次只能从一个程序读取数据库,这将消除这个问题。昨天成功完成了四个进程的运行,我认为这解决了问题,但今天它在选择井查询中仍然存在相同的错误,即使我只使用一个进程运行它也是如此。
(当我认为这是一个解决方案并现在已将其删除时,我将其发布为答案)
也不是说当使用这种方法时,cpu 使用率永远不会超过 80%,因为进程必须等待彼此查询,并且仍然会出错。这意味着 ODBC 驱动程序与 db 的接口必须对使用有一些编码限制。
你认为是什么导致了这个错误,我应该如何解决它?
如果您想查看更多代码,请告诉我哪个部分(有很多)。
【问题讨论】:
-
您能否发布完整的回溯,因为 System Resource Exceeded 没有出现在帖子中?此外,这是一个 MS Access 错误,而不是 Python 错误。通常,此消息涉及复杂的查询、NULL 值的处理、保留字和语法项。
-
另外,作为测试,您能否在 MSAccess.exe 中运行相同的操作(如果您有可用的 Office 程序)?并且
DISTINCT和LEFT JOIN并没有进行太多优化。 -
@Parfait 我已经在 Access 中运行了良好的选择查询,它工作正常。我不确定如何运行整个操作:连续运行 100 个 Select 查询。除了手动操作之外,这需要一个多小时的点击时间。除了通过 pyodbc 接口对每种化学品都有效的查询之外,它只是不能一次全部有效。
-
你见过this question吗?你在运行 32 位 Python 吗?如果是这样,是否有可能切换到 64 位 Python(和 64 位 Access 数据库引擎)?另外,您确定运行多个进程真的会加速您的应用程序吗?
-
@GordThompson 实际上有64 bit drivers。我现在就试试。
标签: python sql ms-access pyodbc