使用子查询可提升 COUNT DISTINCT 速度 50 倍
注:这些技术是通用的,只不过我们选择使用Postgres的语法。使用独特的pgAdminIII生成解释图形。
很有用,但太慢
Count distinct是SQL分析时的祸根,因此它是我第一篇博客的不二选择。
首先:如果你有一个大的且能够容忍不精确的数据集,那像HyperLogLog这样的概率计数器应该是你最好的选择。(我们会在以后的博客中谈到HyperLogLog。)但对于需要快速、精准答案的查询,一些简单的子查询可以节省你很多时间。
让我们以我们一直使用的一个简单查询开始:哪个图表的用户访问量最大?
| 
 1 
2 
3 
4 
5 
6 
7 
 | 
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.idgroup by name order by count desc | 
首先,我们假设user_id和dashboard_id上已经设置了索引,且有比图表和用户数多得多的日志条目。
一千万行数据时,查询需要48秒。要知道原因让我们看一下SQL解析:
它慢是因为数据库遍历了所有日志以及所有的图表,然后join它们,再将它们排序,这些都在真正的group和分组和聚合工作之前。
先聚合,然后Join
group-聚合后的任何工作代价都要低,因为数据量会更小。group-聚合时我们不需使用dashboards.name,我们也可以先在数据库上做聚集,在join之前:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
 | 
select  dashboards.name,  log_counts.ctfrom dashboardsjoin (  select    dashboard_id,    count(distinct user_id) as ct  from time_on_site_logs   group by dashboard_id) as log_counts on log_counts.dashboard_id = dashboards.idorder by log_counts.ct desc | 
现在查询运行了20秒,提升了2.4倍。再次通过解析来看一下原因:
正如设计的,group-聚合在join之前。而且,额外的我们可以利用time_on_site_logs表里的索引。
首先,缩小数据集
我们可以做的更好。通过在整个日志表上group-聚合,我们处理了数据库中很多不必要的数据。Count distinct为每个group生成一个哈希——在本次环境中为每个dashboard_id——来跟踪哪些bucket中的哪些值已经检查过。
我们可以预先计算差异,而不是处理全部数据,这样只需要一个哈希集合。然后我们在此基础上做一个简单的聚集即可。
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
 | 
select  dashboards.name,  log_counts.ctfrom dashboards join (  select distinct_logs.dashboard_id,   count(1) as ct  from (    select distinct dashboard_id, user_id    from time_on_site_logs  ) as distinct_logs  group by distinct_logs.dashboard_id) as log_counts on log_counts.dashboard_id = dashboards.idorder by log_counts.ct desc | 
我们采取内部的count-distinct-group,然后将数据拆成两部分分成两块。第一块计算distinct (dashboard_id, user_id) 。第二块在它们基础上运行一个简单group-count。跟上面一样,最后再join。
呵呵,大发现:这样只需要0.7秒!这比上面的查询快28倍,比原来的快了68倍。
通常,数据大小和类型很重要。上面的例子受益于基数中没多少换算。distinct (user_id, dashboard_id)相对于数据总量来说数量也很少。不同的对数越多,用来group和计数的唯一数据就越多——代价便会越来越大。
下一遇到长时间运行的count distinct时,尝试一些子查询来减负吧。
原文地址:https://periscope.io/blog/use-subqueries-to-count-distinct-50x-faster.html
使用子查询可提升 COUNT DISTINCT 速度 50 倍的更多相关文章
- Impala的count(distinct QUESTION_ID) 与ndv(QUESTION_ID)
		
在impala中,一个select执行多个count(distinct col)会报错,举例: select C_DEPT2, count(distinct QUESTION_BUSI_ID) as ...
 - postgresql子查询优化(提升子查询)
		
问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...
 - volatile 函数影响子查询提升
		
我们知道 volatile 函数会影响SQL的执行性能,比如:volatile 类型函数无法建函数索引.volatile 函数针对每条记录都要执行一次.本篇的例子主要讲述 volatile 类型的函数 ...
 - SQL夯实基础(四):子查询及sql优化案例
		
首先我们先明确一下sql语句的执行顺序,如下有前至后执行: (1)from (2) on (3) join (4) where (5)group by (6) avg,sum... (7 ...
 - MySQL高级查询与编程笔记 • 【第3章 子查询】
		
全部章节 >>>> 本章目录 3.1 子查询定义和单行子查询 3.1.1 子查询定义 3.1.2 单行子查询应用 3.1.4 实践练习 3.2 多行子查询应用 3.2.1 ...
 - 【T-SQL基础】03.子查询
		
以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化. 本系列[T-SQL基础]主要是针对T-SQL基础的总结. [T-SQL基础]01.单表查询-几道sql查询题 ...
 - sql之独立子查询和相关子查询总结
		
1.独立子查询:顾名思义:就是子查询和外层查询不存在任何联系,是独立于外层查询的: 下面就看一个例子: 有一张订单表 Sales.Order 和一张 客户表 Sales.Customer 下面的sql ...
 - SQL Fundamentals: 子查询 || WHERE,HAVING,FROM,SELECT子句中使用子查询,WITH子句
		
SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5 ...
 - MySQL子查询的优化
		
本文基于MySQL5.7.19测试 创建四张表,pt1.pt2表加上主键 mysql> create table t1 (a1 int, b1 int); mysql> create ta ...
 
随机推荐
- linux的cat命令
			
1 描述 cat 的全称 concatenate files and print on the standard output cat命令事Linux下的一个文本输出命令. 用于链接文件并打印到标准输 ...
 - Python 之ConfigParser 学习笔记
			
一.ConfigParser简介 ConfigParser 是用来读取配置文件的包.配置文件的格式如下:中括号“[ ]”内包含的为section.section 下面为类似于key-value 的配置 ...
 - CURL实现HTTP的GET POST方法
			
Curl是Linux下一个非常强大的http命令行工具,其功能十分强大. 一.CURL对HTTP的常规訪问 1. 訪问站点 $ curl http://www.linuxidc.com 回车之后.ww ...
 - java 常见判断题
			
1 根据下面的代码,String s = null;会抛出NullPointerException异常的有(). ) ) ) ) ) ) ) ) 说明:逻辑运算符:&&和|| 是按照“ ...
 - Cordic算法简介
			
作者:桂. 时间:2017-08-14 19:22:26 链接:http://www.cnblogs.com/xingshansi/p/7359940.html 前言 CORDIC算法常用来求解信号 ...
 - Android开发2——创建测试项目
			
一.创建普通Android项目 二.在AndroidManifest.xml添加两个配置 <?xml version="1.0" encoding="utf-8 ...
 - 创建者模式Builder
			
创建者模式: 分离对象子组件的单独构造(由Builder来负责)和装配(由Director负责),对象的构造比较复杂时使用 该模式. 类图: Builder 抽象建造者接口,规范各个组成部分的构建. ...
 - SQL Developer 警告--无法安装某些模块
			
第一次启动正常,第二次启动就开始报错,说无法安装某写模块.具体如下: 警告--无法安装某些模块(Warning - could not install some modules) 在oracle官方的 ...
 - 每日英语:A New Recipe for Innovation That Feeds the Whole Organization
			
The world is a fast and dangerous place. To survive a company must innovate. Many organizations look ...
 - centos7  nginx安装 及MySQL-python
			
1.pip install MySQL-python 出错问题 pip install -r requirement.txt 发现安装MySQL-python 出错,更新setuptools也没用 解 ...