0

ColdFusion で SQL クエリとクエリ オブ クエリを組み合わせて使用​​したプロジェクトを書き直さなければなりません。元の SQL クエリの結果セットを参照する多数のクエリがありましたが、さまざまなイベントで機能するように抽象化されていませんでした。そこで、ほとんどのカウントを SQL に移行して改善したいと思います。彼らが必要とする最初の6つのカウントを取得しました(最適な方法かどうかはわかりません)。しかし、これらに加えて、日付範囲全体だけでなく、その日付範囲内の個々の日ごとの一意のカウントについても分析できる必要があります。

これまでのところ、クエリは次のとおりです。

 SELECT Count(CASE
           WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
           ELSE NULL
         END)              AS total_scans,
   Count(CASE
           WHEN type IN ( 2, 8 ) THEN barcode
           ELSE NULL
         END)              AS total_creds,
   Count(barcode)          AS total_scans,
   Count(DISTINCT CASE
                    WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
                    ELSE NULL
                  END)     AS unique_scans,
   Count(DISTINCT CASE
                    WHEN type IN ( 2, 8 ) THEN barcode
                    ELSE NULL
                  END)     AS unique_creds,
   Count(DISTINCT barcode) AS unique_scans 
FROM   (SELECT c.id,
           a.barcode,
           d.type,
           c.location,
           Datepart(mm, a.scan_time)     AS scan_month,
           Datepart(dd, a.scan_time)     AS scan_day,
           Datepart(hour, a.scan_time)   AS scan_hour,
           Datepart(minute, a.scan_time) AS scan_min
    FROM   [scan_11pc_gate_entries] AS a
           INNER JOIN scan_units AS b
                   ON a.scanner = b.id
           INNER JOIN scan_gates AS c
                   ON b.gate = c.id
           INNER JOIN [scan_11pc_gate_allbarcodes] AS d
                   ON a.barcode = d.barcode
    WHERE  ( c.id IN (SELECT id
                      FROM   scan_gates
                      WHERE  ( event_id = 21 )) )
           AND ( a.valid IN ( 1, 8 ) )
           AND a.scan_time >= '20110808'
           AND a.scan_time <= '20110814') data  
4

1 に答える 1

0

ここには他にも改善/最適化の余地がたくさんありますが、差し迫った要件を満たすために:

 SELECT d, Count(CASE WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
           ELSE NULL END) AS total_scans,
   Count(CASE WHEN type IN ( 2, 8 ) THEN barcode
           ELSE NULL END) AS total_creds,
   Count(barcode)         AS total_scans,
   Count(DISTINCT CASE WHEN type IN ( 1, 3, 4, 5, 9 ) THEN barcode
           ELSE NULL END) AS unique_scans,
   Count(DISTINCT CASE WHEN type IN ( 2, 8 ) THEN barcode
           ELSE NULL END) AS unique_creds,
   Count(DISTINCT barcode) AS unique_scans 
FROM   (SELECT c.id, -- is this column necessary?
           a.barcode,
           d.type,
           c.location, -- is this column necessary?
           d = DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0)
    FROM   [scan_11pc_gate_entries] AS a
           INNER JOIN scan_units AS b
                   ON a.scanner = b.id
           INNER JOIN scan_gates AS c
                   ON b.gate = c.id
                  AND c.event_id = 21 -- join criteria, 
                     -- shouldn't be an extra IN clause
           INNER JOIN [scan_11pc_gate_allbarcodes] AS d
                   ON a.barcode = d.barcode
    WHERE  ( a.valid IN ( 1, 8 ) )
           AND a.scan_time >= '20110808'
           AND a.scan_time <= '20110814') data  
GROUP BY d
ORDER BY d;

>=and<=は と同じであり、 が列BETWEENでない限り(または常に真夜中にあることが保証されている場合)、使用しているアプローチは安全ではないことに注意してください。より良い言い方:scan_timeDATE

           AND a.scan_time >= '20110808'
           AND a.scan_time <  '20110815'

詳細はこちら:


編集

これがコメントや質問から集めた情報に基づいていることを理解すると、これは環境とワークロードの全体像からは程遠いものであり、有用なインデックス付きビューは次のようになります。

CREATE VIEW dbo.myview 
WITH SCHEMABINDING
AS
  SELECT c.event_id,
         a.barcode,
         [type] = CASE WHEN d.[type] IN (2,8) THEN 'c' ELSE 's' END,
         scan_date = DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0),
         total = COUNT_BIG(*)
    FROM dbo.scan_11pc_gate_entries AS a
    INNER JOIN dbo.can_units AS b
            ON a.scanner = b.id
    INNER JOIN dbo.scan_gates AS c
            ON b.gate = c.id
    INNER JOIN dbo.scan_11pc_gate_allbarcodes AS d
            ON a.barcode = d.barcode
    WHERE (a.valid IN (1,8))
      AND d.[type] IN (2,3,4,5,8,9)
    GROUP BY 
      c.event_id,
      a.barcode,
      CASE WHEN d.[type] IN (2,8) THEN 'c' ELSE 's' END,
      DATEADD(DAY, DATEDIFF(DAY, 0, a.scan_time), 0);
GO
CREATE UNIQUE CLUSTERED INDEX x 
  ON dbo.myview(event_id, barcode, [type], scan_date);

これで、次のようなクエリを作成できます。

SELECT [date] = CONVERT(CHAR(8), scan_date, 112), 
  SUM(CASE WHEN [type] = 's' THEN total ELSE 0 END) AS total_scans,
  SUM(CASE WHEN [type] = 'c' THEN total ELSE 0 END) AS total_creds,
  COUNT(CASE WHEN [type] = 's' THEN 1 END) AS unique_scans,
  COUNT(CASE WHEN [type] = 'c' THEN 1 END) AS unique_creds
FROM dbo.myview WITH (NOEXPAND) -- in case STD Edition
WHERE event_id = 21
  AND scan_date BETWEEN '20110808' AND '20110814'
GROUP BY scan_date
UNION ALL
SELECT [date] = 'weekly', 
  SUM(CASE WHEN [type] = 's' THEN total ELSE 0 END) AS total_scans,
  SUM(CASE WHEN [type] = 'c' THEN total ELSE 0 END) AS total_creds,
  COUNT(DISTINCT CASE WHEN [type] = 's' THEN barcode END) AS unique_scans,
  COUNT(DISTINCT CASE WHEN [type] = 'c' THEN barcode END) AS unique_creds
FROM dbo.myview WITH (NOEXPAND) -- in case STD Edition
WHERE event_id = 21
  AND scan_date BETWEEN '20110808' AND '20110814'
ORDER BY [date];

スキーマはシステムの完全な再現を試みて作成するのが少し面倒なので、これはすべて完全にテストされていませんが、うまくいけば、これにより作業の一般的なアイデアが得られます...

于 2013-03-29T19:43:43.787 に答える