用子查詢計算非重複條目,加速五十倍!

本文說的這個技術是通用的,但爲了解釋說明,咱們選用了 PostgreSQL。感謝 pgAdminIII 提供的解釋性插圖,這些插圖有很大幫助。html

頗有用,可是卻很慢

計算非重複的數目是SQL分析的一個災難,顯然,咱們要在第一篇博文上討論。算法

首先一點:咱們若是有一個很大的數據集並且能夠容忍它不精確。一個像 HyperLogLog 的機率統計器多是你的首選(咱們在之後的博客中會講到HyperLogLog ),可是要追求快速精準的結果,子查詢的方法會節省你不少時間。數據庫

讓咱們從一個簡單的查詢語句開始吧:哪個dashboard用戶訪問的最頻繁。segmentfault

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
group by name
order by count desc

首先,讓咱們假設在user_id 和 dashboard_id上都有高效的索引,而且日誌行數要比user_id 和 dashboard_id多不少。工具

僅僅一千萬行數據,查詢語句就花費了48秒的時間。知道爲何嗎?讓咱們看一下明瞭的圖解吧。性能

explain slow

慢的緣由是數據庫要遍歷dashboards表和logs表的全部記錄,而後JOIN操做,而後排序,以後才進行實際須要的分組和彙集操做。spa

先彙集,而後聯合數據表

分組和彙集以後,一切數據庫操做的代價都變小了,由於數據的數量變小了。在分組和彙集的時候,由於咱們不須要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 
  group by dashboard_id
) as log_counts 
on log_counts.dashboard_id = dashboards.id
order by log_counts.ct desc

語句運行了24秒,得到了2.4倍的性能提升。在來看一下,圖解能夠清楚無誤的代表緣由。code

explain faster

像咱們預期地那樣,join操做以前先進行了group-and-aggregate操做。快上加快,咱們還能夠在time_on_site_logs 表上加上索引。htm

第一步,讓你的數據變小

咱們還能夠作的更好,咱們對日誌表作group-and-aggregate操做時,咱們處理了一些無關的數據,其實沒有必要。咱們能夠對每一個分組上建立一個哈希集合,這樣,在每一個哈希桶中讓每一個dashboard_id 挑出那些須要被看處處理的數據。

不用作那麼多工做,只用一個哈希集合,咱們就能夠先去除那些重複的值。而後咱們在這個結果上作彙集操做。

select
  dashboards.name,
  log_counts.ct
from 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.id
order by log_counts.ct desc

咱們讓去重和分組彙集一步一步進行,分紅兩個階段。首先在(dashboard_id, user_id)對上去重,而後在這基礎上作簡單快速的分組計算工做,JOIN操做仍是放在最後。

explain fastest

讓咱們來揭曉最終效果:總共花費了0.7秒,是上一次的28倍,最初的68倍。

通常來講,數據大小和數據位置是很重要的,表中的屬性字段的可能取值個數相對不多,因此纔有那麼明顯的效果,與數據總量相比較,(user_id, dashboard_id) 對的不一樣值不多。越多的不一樣的值,各行的數據越分散,因此分組和計算它們花費越長的時間,果真天下沒有白吃的午飯。

也許你下次計算非重複結果須要花費一天的時間,試着用子查詢的方法減輕它的負載。

要問一下,大家是何許人也?

咱們作了 Periscope,一個可使SQL數據分析更快的工具。咱們在這裏分享一下咱們的工具蘊含的算法和技術。你能夠到咱們的主頁上註冊,從而做爲咱們的新客戶,咱們能夠通知你相關事宜。


原文:Use Subqueries to Count Distinct 50X Faster
轉載於:伯樂在線 - sunbiaobiao

相關文章
相關標籤/搜索