2
CREATE TABLE [arsenal] (
  [id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
  [agent] INTEGER NOT NULL, 
  [haul] DECIMAL NOT NULL, 
  [target] INTEGER NOT NULL);

INSERT INTO arsenal (agent, haul, target) VALUES (1, 10, 2), (1, 100, 2), (2, 20, 1), (2, 200, 1);

こんな感じのテーブルがあります。各ユーザーのすべての の合計を取得したいのですhaulが、ユーザーは と の 2 つの列に分散していagentますtarget。たとえば、ユーザー ID = 1 のエージェントの合計は 110 ですが、ターゲット フィールドの同じユーザーの合計は 220 です。したがって、有効合計は 110 + 220 = 330 です。同様に、ユーザー ID = 2 の有効合計は 330 (エージェント列に 220、ターゲット列に 110)。

私の情報源が次の場合:

id  agent   haul    target
1      1     10        2
2      1     100       2
3      2     20        1
4      2     200       1

、出力が必要です:

user haul
1    330
2    330

. 私はそれを達成することができます:

SELECT   user, SUM(sum) 
FROM     ( 
          SELECT   agent AS user, SUM(haul) AS sum
          FROM     arsenal 
          GROUP BY agent

          UNION ALL

          SELECT   target, SUM(haul)
          FROM     arsenal 
          GROUP BY target
         ) AS t

GROUP BY user;

Union All に関する実際の選択クエリはもう少し複雑であるため、Union を取り除こうとしているため、それがボトルネックであると想定しています。これを達成するためのより良い方法はありますか?サブクエリがなくてもかまいませんか?

これは非常によく似たスレッドですが、答えは私には魅力的ではありません。ありがとう

編集:実際のクエリは次のとおりです。

SELECT   user, SUM(sum) 
FROM     ( 
          SELECT   agent AS user, SUM(haul) AS sum
          FROM     arsenal AS a

          JOIN bucket AS b ON b.parent_id=a.id
          JOIN region AS r ON r.terminal = b.terminal
          WHERE a.status=@status AND r.savedStatus=@savedStatus

          GROUP BY agent

          UNION ALL

          SELECT   target, SUM(haul)
          FROM     arsenal 

          JOIN bucket AS b ON b.parent_id=a.id
          JOIN region AS r ON r.terminal = b.terminal
          WHERE a.status=@status AND r.savedStatus=@savedStatus

          GROUP BY target
         ) AS t

GROUP BY user;

さらに、s にはさらに多くのフィールドがありますSELECT。ここで注意すべきことは、まったく同じクエリが両方SELECTの in で2 回実行されていることUNIONです。したがって、私は完全に回避し、冗長性を回避するためにUNION何らかの方法に依存しようとしています。JOIN

4

1 に答える 1

2

結合を回避するには、別のテーブルに参加して、行数を効果的に2倍にする ことができます。(現在、UNION ALLは行を2倍にします。)

  Agent
INNER JOIN
  Haul
    ON Agent.ID = Haul.Agent
    OR Agent.ID = Haul.Target

ただし、結合で使用できるインデックスは1つだけです。また、単一のインデックスがOR条件を効果的に満たすことはありません。 これらの両方の基準を満たすようにレコードを並べ替えることはできません。同じエージェントのレコードは互いに隣接しており、同じターゲットのレコードは互いに隣接しています。)

ここでの通常のSQLコードの最適化は、気に入らないUNIONALLです。

これは、次のフィールドを使用して、エージェントフィールドとターゲットフィールドを正規化されたテーブルに移動することで解決できます。
-Haul_ID
-Agent_ID
-Is_Target

これは、運搬ごとにすでに2つのレコードがあります...

  HaulAgentMap
INNER JOIN
  Haul
    ON Haul.ID = HaulAgentMap.Haul_ID

HaulAgentMapの単一のインデックスも、すべての適切なレコードを隣り合わせに保持します。

一般に、このタイプの正規化は、コードとパフォーマンスにメリットをもたらします。保守性、適応性なども

(間違いでごめんなさい、私は電話中です...)


編集

コードの繰り返しを減らすために、パフォーマンスを変更する可能性は低いですが、ユニオンに参加するだけです...

(
  SELECT id, Agent, val FROM haul
  UNION ALL
  SELECT id, Target, val FROM haul
)
  AS haul
INNER JOIN
  etc, etc

RDBMSは通常、クエリプランを生成するときにこれを拡張します。つまり、元のクエリと同じように機能しますが、コードの繰り返しは少なくなります。

于 2012-11-10T07:54:26.200 に答える