2017-10-21 6 views
1

私は日付付きの一意のレコードを含むDjangoモデルを持っています。私は現在、レコードを数日の範囲に数えています。 X番号はすでに日付に達しており、Xは10日以内に、Xは次の30日以内に発生します。 以下のコードは、私が現在使っているコードです。モデルに対するrecords.objects.all()クエリからすべての値を取得し、各オブジェクトをループしてdatetimeデルタを計算し、関連するカウンタをインクリメントします。周りの50,000レコードの場合datetime diffsの実行日の計算

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 

これは、私は、レコードの数が増加する可能性があるとして、これを削減しようとしている、もはや私は希望よりもあるおよそ5~6秒かかります。 質問は実際にはdatetime diffのパフォーマンス計算を行い、Django Queryやその他の方法でより良いメソッドがあるかのように結果の日数をグループ化しています。

未処理のSQLでDateAddの使用方法を調べましたが、各日付範囲のデータベースにクエリする必要があり、結果をループする必要があります。

+0

サンプルデータと所望の出力とhttp://www.rextester.comデモをご用意ください。私は純粋なSQLでは1秒以下の時間を得ることができると確信しています。 – lad2025

+1

http://rextester.com/AWPX46055 - 私はそれを正しいと思っています。望ましい出力は、上記のグループによる数字の返却に過ぎず、30日以内に10日以内に渡されます。私はまた30日以上何かの将来の必要性を参照してください。内部の日付は累積されています。 – Draineh

+1

サンプルデータをありがとう – lad2025

答えて

1

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; 

Rextester Demo

+1

これは完璧なおかげです。 – Draineh

1

パフォーマンスを最適化する前に、バッチ単位での実行を検討します。あなたの最も小さなウィンドウは1日であるように見えます。レコードモデルの「更新済み」フィールドでフィルタリングすることで、1時間ごとに(cronあたり)

from datetime import datetime, timedelta 
records.objects.filter(updated__lt = datetime.now()-timedelta(days=1))[:2083] 

を呼び出して操作することができます。 取得するレコードの数を制限することができます。毎時間、2083(または5000)のレコードが処理され、その日にタスクが分割されます。この数値は、データベース内のレコード数に基づいて調整することができます(例:50000/24 = 2083)

マイグレーションでは過去のライブレコードをすべて設定してライブレコードを1回処理する最初はSQLを使用して

+0

最小のウィンドウが1日であることは間違いありません。現時点で私は結果を取り上げてユーザーに直接提示しています(問題の一部)。このアプローチでは、私は結果をキャッシュして、ユーザーがその時間を計算するのではなく、数値を表示するたびに呼び出すことができると思います。 – Draineh

+1

はい、ここでのポイントは、 'Model.objects.all()'データベースのストレスを軽減するために、フィルタリングについて考える必要があります。あなたが他のフィルタリング方法を見つけることができれば、それは良いことです。例えば。ユーザーがアクションを実行すると、そのユーザーに関連付けられているすべてのレコードを更新します。バッチ毎時は徹底した解決策であり、忘れたレコードを避けることができます。 – rollinger