【发布时间】:2021-11-11 07:41:09
【问题描述】:
我有一个 MSSQL 存储过程,它返回 4 个选项给我:Entities、Certificates、Contacts 和 Logs。我需要在 Pyton 中组合这 4 个选项,我将所有 Entities、Contacts 和 Logs 放在它们的 Certificate 下。这些选择中的每一个都有一个 EntityId 我可以用于合并。
输入是简单的基本数据类列表,其中包含来自 SQL 的信息。我们在合并函数中将这些数据类转换为字典。
当我最初编写代码时,我不知道选择可能非常大(Certificates 的 100.000 个及其所有其他记录)。不幸的是,由于循环内列表推导的许多不必要的迭代,这使得下面的代码非常低效。最多可能需要 70 秒。我确信有一种方法可以使这更快。如何提高性能以尽可能高效?
from dataclasses import asdict
def cert_and_details(entities: List[Entity],
certificates: List[Certificate],
req_logs: List[DocumentRequestHistory],
recipients: List[Recipient]) -> List[dict]:
entities = [asdict(ent) for ent in entities]
certificates = [asdict(cert) for cert in certificates]
req_logs = [asdict(log) for log in req_logs]
recipients = [asdict(rec) for rec in recipients]
results = []
for cert_dict in certificates:
cert_entity_id = cert_dict["entityid"]
logs_under_cert = [log for log in req_logs if log["entityid"] == cert_entity_id]
cert_dict["logs"] = logs_under_cert
entities_under_cert = [ent for ent in entities if ent["entityid"] == cert_entity_id]
cert_dict["linkedentity"] = entities_under_cert
recipients_under_cert = [rec for rec in recipients if rec["entityid"] == cert_entity_id]
cert_dict["recipients"] = recipients_under_cert
results.append(cert_dict)
return results
【问题讨论】:
-
可能最好的起点是改进 SQL 查询。您可以进行查询,以便
logs、ents和recipients已经针对entityid进行过滤,然后您不需要在 for 循环中执行所有列表推导。 -
这是一种可能性,也是我们想到的。但是,无论我们走哪条路,我仍然想知道在 Python 中解决此类问题的最佳答案是什么。
-
列表推导可能在不使用任何库的情况下尽可能快。使用
numpy过滤列表可能有更优化的方法,但是,我对此并不十分熟悉。在代码结构方面,您可以通过创建一个dict来优化此代码,其中entityid作为键,其余的值作为您需要的值。然后,您只需要在开始时对所有列表进行一次迭代,并且在主循环中,您可以在 O(1) 时间内简单地访问每个字段。如果这对您有帮助,请告诉我,以便我可以将其升级为答案。 -
这可能会有所帮助。如果没有人给出一个 numpy 的答案,我很乐意看看它。
-
与许多软件开发一样,“最佳答案”通常与上下文相关。换句话说,这取决于。您说 70 秒对于处理数据来说太长了,但什么是可接受的目标,您是否创建了一个基准来测试替代方案?
logs_under_cert、entities_under_cert和recipients_under_cert的赋值看起来像是代码中的连接,而不是 SQL 查询的一部分。大多数情况下,选择正确的算法和数据结构是您获得最佳答案的地方。
标签: python performance rest record python-dataclasses