繁体   English   中英

查询多个子查询效率?

[英]Query With Multiple Subqueries Efficiency?

我的数据如下所示:

State   Sex
----    ---
GA      M
GA      M
GA      F
GA      F
GA      F
NY      M
NY      M
NY      M
NY      M
NY      F
NY      F
NY      F
NY      F
NY      F

我希望结果是:

  1. 每个 state 一行
  2. col1 State
  3. col2 男性数量
  4. col3 女性数量
  5. state 的 col4 总计数
  6. col 5% 男性 by state

我正在使用的查询是:

select t.state State, 
M.count Male, 
F.count Female, 
count(t.state) Total,
CONCAT(ROUND(CAST(M.count as float)/CAST(count(t.state) as float)*100, 2), '%') as calc
from MyTable t
join
(
  select state, count(sex) as count 
  from MyTable where sex ='M' 
  group by state) M 
  on t.state = M.state 
join (
  select state, count(sex) as count 
  from MyTable where sex ='F' 
  group by state) F 
  ON M.state = F.state
  group by t.state, m.count, F.count;

上面的查询有效,但我想知道我是否以最有效的方式做到了这一点。 这是使用 SQLServer 完成的,但我认为这对于所有 RDBMS 应该是相同的。 链接在这里: http://sqlfiddle.com/#!18/7a969/87

使用条件聚合:

select t.state, 
       sum(case when sex = 'M' then 1 else 0 end) as males,
       sum(case when sex = 'F' then 1 else 0 end) as females,
       count(*) as total,
       avg(case when sex = 'M' then 1.0 else 0 end) as male_ratio
from MyTable t
group by t.state;

我希望这将是几乎所有数据库中最快的方法。

是 SQL 小提琴。

您可以通过从每个 state 的总计数中减去男性人数来计算女性人数。 这样,只需要一个join

with r as (select t.state s, count(*) c from testtable t group by t.state)
select r1.s, t1.m males, r1.c - t1.m females, r1.c total, 100*(t1.m/r1.c) m_percent 
from r r1 
join (select t.state s, t.sex, count(*) m from testtable t group by t.state, t.sex) t1 on r1.s = t1.s where t1.sex = "M"; 

Output:

state 男性 女性 全部的 m_percent
遗传算法 2 3 5 40.0000
纽约 4 5 9 44.4444

演示

没有必要将数据分离到MaleFemale的表中。 从性能的角度来看,如果子查询能够以最佳方式使用索引,则可能有助于提高性能,但实际上您仅对索引值进行聚合的可能性很小。

对于这个简单的查询,您可以使用简单的CASE表达式内联将Male / Female列表示为BIT值,然后我们可以在单个聚合中对这些值求和,但是这需要您为Male定义CASE两次,因此您可以使用它在Male列和% Male中。

我们可以使用CROSS APPLY代替内联CASE作为对每一行解析一次计算的方法,并允许您引用结果:

SELECT t.state State, 
SUM(Calcs.IsMale) Male, 
SUM(Calcs.IsFemale) Female, 
COUNT(1) Total,
CONCAT(ROUND(SUM(Calcs.IsMale)/CAST(COUNT(1) as float)*100, 2), '%') as Calc
FROM MyTable t
CROSS APPLY (SELECT 
     CASE Sex WHEN 'M' THEN 1 END as [IsMale]
    ,CASE Sex WHEN 'F' THEN 1 END as [IsFemale]
) as calcs
GROUP BY [State]

这是否更有效? 一般来说,这个执行计划应该比加入多个聚合集简单得多,但是如果没有更大的数据集来测试它,就很难说。

无论哪种方式,我都希望这个简单的 CROSS 应用版本能够获胜,因为我们只需要处理一次结果集。

在给定数据集上运行原始和 CROSS APPLY 并查看实际执行计划时,SQL Sever 报告 CROSS APPLY 查询为批处理相对成本的 25%:

我提前道歉将其作为图片发布,不确定是否有更好的方式进行讨论

执行计划,OP 嵌套连接与交叉应用

这个执行计划报告说 Original Query 是 CROSS APPLY 版本的成本的 3 倍,这可能是由于第一个查询中的 3 次扫描,而 CROSS APPLY 版本中的单表扫描

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM