用子查询计算非重复条目,加速五十倍!

简介: 本文说的这个技术是通用的,但为了解释说明,我们选用了 PostgreSQL。感谢 pgAdminIII 提供的解释性插图,这些插图有很大帮助。

本文说的这个技术是通用的,但为了解释说明,我们选用了 PostgreSQL。感谢 pgAdminIII 提供的解释性插图,这些插图有很大帮助。


很有用,但是却很慢

计算非重复的数目是SQL分析的一个灾难,显然,我们要在第一篇博文上讨论。

首先一点:我们如果有一个很大的数据集而且可以容忍它不精确。一个像 HyperLogLog 的概率统计器可能是你的首选(我们在以后的博客中会讲到HyperLogLog ),但是要追求快速精准的结果,子查询的方法会节省你很多时间。

让我们从一个简单的查询语句开始吧:哪一个dashboard用户访问的最频繁。

select

 dashboards.name,

 count(distinct time_on_site_logs.user_id)

from time_on_site_logs

join dashboards on time_on_site_logs.dashboard_id = dashboards.id

groupbyname

orderby count desc

首先,让我们假设在user_id 和 dashboard_id上都有高效的索引,并且日志行数要比user_id 和 dashboard_id多很多。

仅仅一千万行数据,查询语句就花费了48秒的时间。知道为什么吗?让我们看一下明了的图解吧。

image.png

慢的原因是数据库要遍历dashboards表和logs表的所有记录,然后JOIN操作,然后排序,之后才进行实际需要的分组和聚集操作。


先聚集,然后联合数据表

分组和聚集之后,一切数据库操作的代价都变小了,因为数据的数量变小了。在分组和聚集的时候,因为我们不需要dashboards.name,所以我们可以在JOIN操作前先进行聚集操作:

select

 dashboards.name,

 log_counts.ct

from dashboards

join (

 select

   dashboard_id,

   count(distinct user_id) as ct

 from time_on_site_logs

 groupby dashboard_id

) as log_counts

on log_counts.dashboard_id = dashboards.id

orderby log_counts.ct desc

语句运行了24秒,获得了2.4倍的性能提高。在来看一下,图解可以清楚无误的表明原因。

image.png

像我们预期地那样,join操作之前先进行了group-and-aggregate操作。快上加快,我们还可以在time_on_site_logs 表上加上索引。


第一步,让你的数据变小

我们还可以做的更好,我们对日志表做group-and-aggregate操作时,我们处理了一些无关的数据,其实没有必要。我们可以对每个分组上创建一个哈希集合,这样,在每个哈希桶中让每个dashboard_id 挑出那些需要被看到处理的数据。

不用做那么多工作,只用一个哈希集合,我们就可以先去除那些重复的值。然后我们在这个结果上做聚集操作。

select

 dashboards.name,

 log_counts.ct

from dashboards

join (

 select distinct_logs.dashboard_id,

 count(1) as ct

 from (

   selectdistinct dashboard_id, user_id

   from time_on_site_logs

 ) as distinct_logs

 groupby distinct_logs.dashboard_id

) as log_counts

on log_counts.dashboard_id = dashboards.id

orderby log_counts.ct desc

我们让去重和分组聚集一步一步进行,分成两个阶段。首先在(dashboard_id, user_id)对上去重,然后在这基础上做简单快速的分组计算工作,JOIN操作还是放在最后。

image.png

让我们来揭晓最终效果:总共花费了0.7秒,是上一次的28倍,最初的68倍。

一般来说,数据大小和数据位置是很重要的,表中的属性字段的可能取值个数相对很少,所以才有那么明显的效果,与数据总量相比较,(user_id, dashboard_id) 对的不同值很少。越多的不同的值,各行的数据越分散,所以分组和计算它们花费越长的时间,果然天下没有白吃的午餐。

也许你下次计算非重复结果需要花费一天的时间,试着用子查询的方法减轻它的负载。


要问一下,你们是何许人也?

我们做了 Periscope,一个可以使SQL数据分析更快的工具。我们在这里分享一下我们的工具蕴含的算法和技术。你可以到我们的主页上注册,从而作为我们的新客户,我们可以通知你相关事宜。


相关文章
|
JavaScript Python 内存技术
error C:\Users\Acer\Downloads\Desktop\hrsaas-84\node_modules\deasync: 莫名其妙报错一堆python问题
error C:\Users\Acer\Downloads\Desktop\hrsaas-84\node_modules\deasync: 莫名其妙报错一堆python问题
495 0
|
2月前
|
数据采集 缓存 监控
小红书 item_search - 关键词取商品列表接口对接全攻略:从入门到精通
小红书商品关键词搜索接口(item_search)为第三方合规封装工具,支持通过关键词批量获取平台内美妆、穿搭、家居等类目商品信息,涵盖价格、销量、评分、店铺及关联笔记数据,适用于选品分析、竞品监测、市场调研等场景。本攻略详解接口核心功能、参数配置、签名生成、Python调用示例及调试优化技巧,结合分页处理、异步请求与缓存策略,助力开发者高效稳定对接,规避合规风险,实现生产级应用。
|
3月前
|
人工智能 安全
Gartner®报告:阿里云位列GenAI云基础设施、工程、模型特性维度全球第三
阿里云在Gartner四大GenAI新兴市场象限中均位列领导者,基础设施、工程、模型及知识管理维度全面领先,其中三项“特性”指标居全球第三、亚太第一,彰显其“云+AI”全栈技术实力与市场竞争力。
179 0
|
9月前
|
网络协议 算法 物联网
Go语言的WebSocket与实时通信
本文介绍了 WebSocket 技术及其在 Go 语言中的实现。WebSocket 是一种基于 TCP 的协议,支持客户端与服务器间的持久连接和实时通信,相比传统 HTTP 更高效。文章详细讲解了 WebSocket 的核心概念、Go 语言中的相关库(如 `gorilla/websocket`),以及其实现步骤和应用场景。通过代码示例展示了如何构建 WebSocket 服务器和客户端,并探讨了其在聊天应用、实时更新、游戏和物联网等领域的实际用途。此外,还推荐了相关工具和学习资源,帮助开发者更好地掌握这一技术。
387 3
|
存储 Java 开发工具
在Eclipse配置安装Android详细教程(新手)
在Eclipse配置安装Android详细教程(新手)
599 1
|
计算机视觉 知识图谱
YOLOv11改进策略【Conv和Transformer】| ACmix 卷积和自注意力的结合,充分发挥两者优势
YOLOv11改进策略【Conv和Transformer】| ACmix 卷积和自注意力的结合,充分发挥两者优势
232 9
|
编解码 API 数据安全/隐私保护
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
【9月更文挑战第21天】本文介绍了如何使用FFmpeg和EasyPusher实现移动端RTSP直播。首先概述了EasyPusher的功能及其API,接着详细描述了安装FFmpeg、获取EasyPusher库、初始化对象、打开输入流、配置推送参数及读取推送帧的具体步骤,并提醒开发者注意网络环境、编码参数和权限管理等问题,以确保直播质量与稳定性。
233 8
|
人工智能 安全 物联网
物联网技术的未来发展趋势
物联网技术的未来发展趋势
537 4
|
存储 Sentinel
链表中哨兵(头结点)的作用
链表中哨兵(头结点)的作用
|
传感器 移动开发 监控
嵌入式物联网设计水稻田智能灌溉系统实现
嵌入式物联网设计水稻田智能灌溉系统实现
949 0