哪个更快,水平计数还是垂直计数?
Posted
技术标签:
【中文标题】哪个更快,水平计数还是垂直计数?【英文标题】:Which is faster, horizontal or vertical counting? 【发布时间】:2010-09-17 21:46:53 【问题描述】:我需要从很多行中获取摘要数据。汇总字段是对不同字段的每个值有多少条目的计数。例如,一个包含人的年龄、城市、工作等的表格,汇总数据将包括每个工作的“countManager”、“countCodeMonkey”等字段,然后是城市的“countChicago”、“countNewYork”等字段。
我知道获取一切的简单方法是:
select count(*) from table
group by age, city, job
但这是垂直计数 - 我需要的每个值都有不同的行。我需要字段而不是带有计数的行,因为我还有其他字段可以分组,例如状态。所以我希望我的结果看起来像这样:
| State | countManager | countMonkey |
| IL | 3 | 25 |
| NY | 5 | 40 |
我正在寻找两种方法来做到这一点。我们已经实现了一个,执行需要 20 分钟。我想知道其他方式是否会更快。
目前的方式是这样的:
create view managers as
select state, count(*) as theCount from table
where job = 'Manager'
group by state;
create view monkeys as
select state, count(*) as theCount from table
where job = 'Monkey'
group by state;
select managers.theCount as managers, monkeys.theCount as monkeys
from managers left join monkeys
on managers.state = monkeys.state;
在实际情况下,大约有 20 个视图,因此还有 20 个连接。
我正在考虑使用以下水平计数方法:
select state,
sum(case when job='Manager' then 1 else 0 end) as managers,
sum(case when job='Monkey' then 1 else 0 end) as monkeys
from table
group by state;
这消除了连接。但我对“sum case”语句的表现一无所知。这会更快,差不多还是慢得多?引擎是否必须多次遍历行,每个这样的计数字段一次?或者它是否足够聪明,可以一次计算所有字段,检查每个值并增加适当的总和?
我可能会花一天的时间编写一个脚本来生成大量垃圾数据来测试这一点,但我仍然想知道 db 引擎的行为,这是我在网上其他地方找不到的。
【问题讨论】:
这可能取决于所涉及的数据库引擎。你想到了哪一个? 如果您有 Microsoft SQL Server,他们有一个查询计划,可以直观地向您展示数据库引擎如何解析/执行您的查询 我相信我们正在使用 Postgres。 第二个对我来说似乎效率更高。它只需要一次通过数据。不过,我对 postgres 的了解还不够,无法肯定地说。 【参考方案1】:完全取决于引擎以及您希望如何查看数据,但您的第二个选项肯定会更快完成。
即使您的第一个查询需要 20 分钟也是荒谬的,除非您实际上有数十亿行。在这种情况下,您应该每月/每周查看存档数据,并在表格中预先编译汇总数据,您可以在表格中进行切片和切块以适合。
【讨论】:
视图可能会变慢,因为索引问题 - 或者更确切地说,缺少索引。【参考方案2】:如果您的事务与其他事务之间没有并发,“sum case”是一个不错的选择。将函数聚合为AVG
、SUM
、GROUP BY
,会降低性能。与两件事保持联系:“分而治之”和“数字数据比文本数据更快”。
创建一个数据仓库(单个表、一个数据库)以避免并发并加快处理速度。
CPU 是了不起的计算器:将您的分类数据("NY"
、"LA"
、"Man"
、"Woman"
)转换为数字数据(1
、2
、61
、62
)和提高您的采矿能力。
清理您对数据库供应商或平台选择的想法,但关系代数。
【讨论】:
以上是关于哪个更快,水平计数还是垂直计数?的主要内容,如果未能解决你的问题,请参考以下文章
对于操作计数()。 std::set<void*> 或 std::unordered_set<void*> 哪个更快?
简单动态规划的实现(Leetcode 338. 比特位计数)