【发布时间】:2014-12-16 09:58:52
【问题描述】:
我最近有一个任务是使用 Propel 在 PostgreSQL 中迭代一个大表(约 40KK 记录),并遇到了性能问题,包括内存限制和执行速度。我的脚本已经运行了 22(!) 小时。
任务是根据某些条件(在过去 6 个月内不活跃)检索记录并将它们存档(移动到另一个表)以及来自其他表的所有相关实体。
我的脚本正在处理的主表有几列:id、device_id、application_id、last_activity_date 和其他列,在这里没有任何意义。此表包含有关安装在设备上的应用程序及其最后活动日期的信息。可能有多个记录具有相同的device_id 和不同的application_id。这是表格中的一个示例:
id | device_id | application_id | last_init_date
----------+-----------+----------------+---------------------
1 | 1 | 1 | 2013-09-24 17:09:01
2 | 1 | 2 | 2013-09-19 20:36:23
3 | 1 | 3 | 2014-02-11 00:00:00
4 | 2 | 4 | 2013-09-29 20:12:54
5 | 3 | 5 | 2013-08-31 19:41:05
因此,如果此表中特定 device_id 的最大 last_activity_date 超过 6 个月,则认为该设备已足够旧,可以存档。这是查询:
SELECT device_id
FROM device_applications
GROUP BY device_id
HAVING MAX(last_init_date) < '2014-06-16 08:00:00'
在 Propel 中它看起来像:
\DeviceApplicationsQuery::create()
->select('DeviceId')
->groupByDeviceId()
->having('MAX(device_applications.LAST_INIT_DATE) < ?', $date->format('Y-m-d H:i:s'))
->find();
如您所知,结果集太大而无法放入内存,因此我必须以某种方式将其拆分为块。
问题是:在这种情况下,减少内存消耗和加快脚本速度的最佳策略是什么? 在我的回答中,我将向您展示我到目前为止发现的内容。
【问题讨论】:
-
为什么不能通过一次查询将所有记录移动到档案中? 40k 条记录并不多。
-
40KK,是4000万
-
4000 万条记录要多得多,但当您的硬件可以处理这么多数据时可能会很快。您是否在单个查询中检查了包含 DELETE 和 INSERT 的公用表表达式? ORM(任何类型的 ORM)和性能始终是一个挑战,ORM 不是为此而生的。
-
是的,我知道ORM一般不适合这种情况,但问题是主要实体(设备)有很多相关实体(实际上是5个其他表,有外键约束)也必须存档。并且归档相关记录的逻辑是在ORM类中实现的。
-
这就是我所做的,我在回答中指出了这一点。
标签: php postgresql pdo propel