以天为单位的日期时间差异的性能计算
Performant calculation of datetime diffs in days
我有一个 Django 模型,其中包含带有日期的唯一记录。我目前正在将记录计入天数范围,例如X 号已经过了今天的日期,X 将在接下来的 10 天内发生,X 将在接下来的 30 天内发生。
下面的代码是我目前正在使用的代码,它从针对模型的 records.objects.all() 查询中提取所有值,然后遍历每个对象以计算日期时间增量并递增相关计数器。
for x in records:
if x.date is None:
missingValue += 1
else:
delta = x.date - date.today()
if delta.days < 0:
passed += 1
if delta.days < 10:
tenDays += 1
if delta.days < 30:
thirtyDays += 1
对于大约 50,000 条记录,这大约需要 5-6 秒,这比我想要的要长,我正在尝试减少它,因为记录的数量可能会增加。
问题实际上是围绕日期时间差异的性能计算和对结果天数进行分组,就好像通过 Django 查询或其他我找不到更好的方法一样,我愿意尝试它。
我探索了 DateAdd 在原始 SQL 中的使用,但它似乎需要我为每个日期范围查询数据库,并且仍然会导致我需要循环遍历结果。
在优化性能之前,我会考虑批量执行。您的最小 window-of-change 似乎是 1 天。因此,通过过滤记录模型中的 'updated' 字段,您可以每小时(每个 cron)调用一个:
from datetime import datetime, timedelta
records.objects.filter(updated__lt = datetime.now()-timedelta(days=1))[:2083]
然后做你的手术。
请注意,您可以限制检索到的记录数。因此,每小时您将处理 2083(或 5000)条记录,将任务分配到一天中。您可以根据数据库中的记录数缩放此数字(例如 50000/24 = 2083)
此外,您的迁移可能想要反映出您希望将其设置为过去很久,以便每条实时记录在开始时都被处理一次。
使用 SQL 窗口 COUNT
:
WITH cte AS (
SELECT *,CASE WHEN DATEDIFF(DAY,GETDATE(),targetdate) <=0 THEN 0
WHEN DATEDIFF(DAY,GETDATE(),targetdate) <=10 THEN 10
WHEN DATEDIFF(DAY,GETDATE(),targetdate) <=30 THEN 30
ELSE 31 END AS grp
FROM [record]
--WHERE targetdate > GETDATE() - 60 -- last 60 days
)
SELECT DISTINCT grp, COUNT(*) OVER(ORDER BY grp) AS running_count
FROM cte;
我有一个 Django 模型,其中包含带有日期的唯一记录。我目前正在将记录计入天数范围,例如X 号已经过了今天的日期,X 将在接下来的 10 天内发生,X 将在接下来的 30 天内发生。 下面的代码是我目前正在使用的代码,它从针对模型的 records.objects.all() 查询中提取所有值,然后遍历每个对象以计算日期时间增量并递增相关计数器。
for x in records:
if x.date is None:
missingValue += 1
else:
delta = x.date - date.today()
if delta.days < 0:
passed += 1
if delta.days < 10:
tenDays += 1
if delta.days < 30:
thirtyDays += 1
对于大约 50,000 条记录,这大约需要 5-6 秒,这比我想要的要长,我正在尝试减少它,因为记录的数量可能会增加。 问题实际上是围绕日期时间差异的性能计算和对结果天数进行分组,就好像通过 Django 查询或其他我找不到更好的方法一样,我愿意尝试它。
我探索了 DateAdd 在原始 SQL 中的使用,但它似乎需要我为每个日期范围查询数据库,并且仍然会导致我需要循环遍历结果。
在优化性能之前,我会考虑批量执行。您的最小 window-of-change 似乎是 1 天。因此,通过过滤记录模型中的 'updated' 字段,您可以每小时(每个 cron)调用一个:
from datetime import datetime, timedelta
records.objects.filter(updated__lt = datetime.now()-timedelta(days=1))[:2083]
然后做你的手术。 请注意,您可以限制检索到的记录数。因此,每小时您将处理 2083(或 5000)条记录,将任务分配到一天中。您可以根据数据库中的记录数缩放此数字(例如 50000/24 = 2083)
此外,您的迁移可能想要反映出您希望将其设置为过去很久,以便每条实时记录在开始时都被处理一次。
使用 SQL 窗口 COUNT
:
WITH cte AS (
SELECT *,CASE WHEN DATEDIFF(DAY,GETDATE(),targetdate) <=0 THEN 0
WHEN DATEDIFF(DAY,GETDATE(),targetdate) <=10 THEN 10
WHEN DATEDIFF(DAY,GETDATE(),targetdate) <=30 THEN 30
ELSE 31 END AS grp
FROM [record]
--WHERE targetdate > GETDATE() - 60 -- last 60 days
)
SELECT DISTINCT grp, COUNT(*) OVER(ORDER BY grp) AS running_count
FROM cte;