1

アクティブ/非アクティブからの変更を記録するn履歴エントリを持つテーブルがあります。

[Id]   [ParentId] [Date]                   [Status]
<guid> 0          2013-05-03 15:51:24.810  'Active'
<guid> 0          2013-05-03 15:52:10.773  'Inactive'
<guid> 0          2013-05-03 15:54:26.710  'Active'
<guid> 0          2013-05-03 17:09:27.327  'Inactive'

履歴全体でアイテムが「アクティブ」ステータスにあった期間を特定しようとしています。カーソルを使用して履歴を反復し、それを使用DATEDIFFして計算すると、ひどいパフォーマンスが得られました。私はSQLCLRの使用を避けようとしていますが、おそらくこれをメモリ内でかなり安価に行うことができます...これを達成するための優れたSQLネイティブでパフォーマンスの高い方法を知っている人はいますか?

4

1 に答える 1

2

重要なアイデアは、特定のアクティブ レコードの後に​​次の非アクティブ レコードを取得することです。

SQL Server 2012 を使用している場合は、lead()関数を使用できます。それ以外の場合は、相関サブクエリが、実行する必要があることを表す最も簡単な方法だと思います。(明示的にこれを行うこともできますjoin。これはより明確だと思います)。

select guid, sum(datediff(ms, t.[date], t.nextInactive)) as duration_ms
from (select t.*,
             (select min([date])
              from t t2
              where t2.guid = t.guid and t2.[date] > t.[date] and t2.status = 'Inactive'
             ) as nextInactive
      from t
      where t.status = 'Active'
     ) t
group by guid

次の非アクティブなレコードを取得したら、差 (この場合はミリ秒) を取り、値を合計します。

最後のレコードがアクティブなレコードである場合、それは無視されます。それをカウントしたい場合coalesce(t.nextInactive, <some value here>)は、外側のクエリで使用する必要があります。

にインデックスがあると、パフォーマンスが向上しますguid, status, date

于 2013-05-07T19:51:55.683 に答える