2

いくつかの日付間隔を分で割る必要があります。(たとえば、2012-01-01 10:00-2012-01-01 10:00間隔は、2012-01-01 10:01、2012-01-01 10:02、...2012-01に分割する必要があります。 -01 10:10)。たとえば、テーブルがあります

CREATE TABLE [dbo].[Events](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [EventStart] [datetime] NOT NULL,
    [EventEnd] [datetime] NOT NULL,
    [Amount] [float] NOT NULL,
 CONSTRAINT [PK_Events] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

このテーブルは次のように入力されます

DECLARE @i integer = 0;
DECLARE @initial_date datetime = '2012-01-01';

WHILE @i < 50000
BEGIN
    INSERT INTO [Events] (EventStart, EventEnd, Amount) VALUES (DATEADD(MINUTE, 10*@i, @initial_date), DATEADD(MINUTE, 10*(@i + 1), @initial_date), @i);
    SET @i = @i + 1;
END

その結果、10分間隔が多くなります。

分で割るには、次の再帰CTEを使用します。

DECLARE @start_date datetime = '2012-01-01';
DECLARE @end_date datetime = '2013-01-02';


WITH Date_Ranges (StatDate, Amount, IntervalStart, CurrentMinute) AS (
  SELECT 
    DATEADD(MINUTE, 0,  ev.EventStart) AS StatDate, ev.Amount, ev.EventStart AS IntervalStart, 1 AS CurrentMinute
  FROM [Events] ev
  WHERE ev.EventStart BETWEEN @start_date AND @end_date
  UNION ALL
  SELECT 
    DATEADD(MINUTE, CurrentMinute, ev.EventStart), ev.Amount, ev.EventStart AS IntervalStart, CurrentMinute + 1
  FROM [Events] ev
  INNER JOIN Date_Ranges ranges ON (ranges.IntervalStart = ev.EventStart AND 
    ranges.StatDate >= ev.EventStart AND 
    ranges.StatDate < ev.EventEnd)
    WHERE DATEADD(MINUTE, CurrentMinute, ev.EventStart) BETWEEN @start_date AND @end_date AND
        ev.EventStart BETWEEN @start_date AND @end_date
) 

SELECT *
FROM Date_Ranges --ORDER BY StatDate

主な問題は、大量のデータに対するこの再帰CTEの実行が遅すぎることです。

では、どうすればこれをスピードアップできますか?

4

2 に答える 2

2

これにより、再帰CTEの約1/2の時間で550,000行すべてが返されます。

DECLARE @start_date datetime = '2012-01-01'; 
DECLARE @end_date datetime = '2013-01-02';

SELECT  DATEADD(MINUTE, x.number, ev.EventStart) AS StartDate, 
        ev.Amount, 
        ev.EventStart as IntervalStart, 
        x.number as CurrentMinute
FROM    master.dbo.spt_values x
CROSS JOIN Events ev
WHERE   x.type = 'P'        
AND     x.number <= DATEDIFF(MINUTE, ev.EventStart, ev.EventEnd)
AND     ev.EventStart BETWEEN @start_date and @end_date
于 2012-10-31T11:26:09.823 に答える
1

最速のバケットセットはテーブルになると思います。10分のバケットのテーブルを作成し、データを入力してから、それに参加します。これにより、再帰が完全に回避され、SQLデータベース管理システムが本当に得意とするものの1つである結合が活用されます。

10分間のバケットの10年間は​​、わずか50万行です。

部品表のようなものを扱っている場合、CTEでの再帰は良いことです。しかし、それは必ずしもテーブルの適切な代替品ではありません。


10年間をカバーする10分のバケットのテーブルを作成しました。(これは約4メガバイトのデータです。ディスクインデックスと行のオーバーヘッドにかかる量を計算しようとはしませんでした。)次に、バケットのテーブルと同じ10年以内に、2,000万のランダムなタイムスタンプを含むテストデータのテーブルを作成しました。 。

問題に適切なインデックスを追加した後、テストシステムは約100ミリ秒でランダムな1日のデータを「バケット」します。(チューニングなしのPostgreSQL dbms、1ギガのRAMを搭載した5年前のDellコンピューターで実行。ここではLinuxシステムを使用しているため、SQL Server自体をテストできませんでした。ただし、同様の結果が期待できます。 )。

于 2012-10-31T10:55:13.710 に答える