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为每个用户获取所有 s 的总和,但用户分布在两列agenttarget. 例如,用户 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;

我试图摆脱联合,因为围绕联合所有的实际选择查询有点复杂,所以我假设这是一个瓶颈。有没有更好的方法来实现这一点,可能没有子查询?

这是一个非常相似的线程,但答案对我没有吸引力。谢谢

编辑:这是实际的查询:

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 中有更多字段SELECTSELECT这里要注意的是,在两个s in中都运行了两次完全相同的查询UNION。所以我试图UNION完全避免并依靠某种JOIN左右来避免冗余。

4

1 回答 1

2

为了避免联合,您可以加入另一个表以有效地将行数加倍。 (您的 UNION ALL 当前将行数加倍。)

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

但是一个连接只能使用一个索引。并且没有一个索引可以有效地满足 OR 条件。 您无法对记录进行排序以使您同时满足这两个条件;同一代理人的记录彼此相邻并且同一目标的记录彼此相邻。)

这里常用的SQL Code优化就是你不喜欢的UNION ALL。

这可以通过将 Agent 和 Target 字段移出到具有以下字段的规范化表中来解决:
- Haul_ID
- Agent_ID
- Is_Target

这将有每个 Haul 的两条记录......

  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 回答