0

さまざまなユーザーからの注文を含むテーブルがあります。各ユーザー (電子メール アドレスで識別) は、任意の数の注文を持つことができます。ユーザーを含む追加のテーブルはありません。単純な OrderData テーブルだけです。私が欲しいものは単純に聞こえます:

  1. 総ユーザー数
  2. XYZ ユーザー数
  3. 非 XYZ ユーザーの数

ここで、1. は 2. と 3. の合計です。「XYZ」ユーザーは、「@xyz.com」で終わる電子メール アドレスによって定義されます。

3 つの列に 3 つの値を返す単一のクエリが必要です。私が現在持っているものは次のとおりです。

SELECT 
    (
    SELECT COUNT(DISTINCT User_EmailAddress)
    FROM OrderData
    WHERE User_EmailAddress IS NOT NULL
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    ) AS [Total Users],
    (
    SELECT COUNT(DISTINCT User_EmailAddress)
    FROM OrderData
    WHERE User_EmailAddress IS NOT NULL
    AND User_EmailAddress LIKE '%@xyz.com'
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    ) AS [XYZUsers],
    (
    SELECT COUNT(DISTINCT User_EmailAddress)
    FROM OrderData
    WHERE User_EmailAddress IS NOT NULL
    AND User_EmailAddress NOT LIKE '%@xyz.com'
    AND RequestTime >= @RequestTimeFrom
    AND RequestTime  < @RequestTimeTo
    ) AS [Non-XYZ Users]

正しい結果セットを返します。

Total Users | XYZ Users | Non-XYZ Users
------------+-----------+--------------
        123 |        23 |           100

基本的に同じコードで 3 つの同様のクエリを作成する代わりに、このクエリを作成するより良い方法はありますか?

4

2 に答える 2

0

bluefeet によって提供されるソリューションには、まだ 1 つの欠点があります。各 DISTINCT 集計 (この場合は COUNT) は、入力行のストリームを個別に消費します。これにより、ベース テーブルの個別のスキャン/シークが発生する可能性があります (個別の集計ごとに 1 セット)。ただし、オプティマイザーがベース テーブルのシーク/スキャンを作業テーブルにスプールしてから、集計を計算できる場合があります。

これを行うためのよりパフォーマンス指向の方法 (この特定のケース) は、合計カウントを変数に取得し、次に xyz カウントを別の変数に取得し、スカラー演算を使用して 3 番目の値 (非 xyz) を推測することです。そうすれば、1 つのスプールのリプレイを回避できます (さらに悪いことに、ベース テーブルのシーク/スキャン演算子)。

詳細については、Paul White による次のブログを参照してください。まだ有害と見なされている.aspx

于 2013-04-12T16:24:56.197 に答える