Citus有多个不同的执行程序,每个执行程序的行为都不同,以支持各种用例。对于许多概念而言,分布式SQL似乎必须是一个复杂的概念,但是其原理并不是火箭科学。在这里,我们将看几个有关Citus如何采用标准SQL并将其转换为以分布式形式运行以便可以并行化的示例。结果是您可以看到单节点数据库的查询性能提高了100倍或更多。

我们如何知道某物是分布式的还是单片?

在了解实时执行器的工作方式之前,值得对Citus执行器进行全面的复习。

当Citus收到查询时,我们首先查看它是否具有where子句的分片键(也称为分发列)。如果您要分拆诸如CRM应用程序之类的多租户应用程序,则可能会有一个org_id,您总是会限制查询。在这种情况下,只要org_id是where子句的一部分,我们就知道它的目标是单个分片,因此可以使用路由器执行程序。如果未使用该查询,我们会将查询拆分并跨节点并行发送给所有分片。

作为快速更新,Citus中的一个表是另一个表。如果您有一个表事件并想要分发它,则可以创建32个分片,这意味着我们可以轻松扩展到32个节点。如果您从2个节点开始,则每个节点包含32个分片。这意味着每个节点将一次接收16个查询,并且如果它有16个可用的内核,那么所有工作将并行完成,从而导致2个节点x 16个内核,或者说,与在单个内核上执行相比,速度提高了32倍。

对于后面的示例,我们将仅创建4个分片以简化它们,但是随着添加的分片和对应的内核的增加,事情几乎线性地扩展。

用SQL编写,用MapReduce思考

Citus对实时分析的支持是自从我们早期以来,人们就一直使用Citus的工作负载,这要归功于我们先进的查询并行化。结果就是您能够用标准SQL表示事物,并让Citus的分布式查询计划器完成重写查询的艰苦工作,从而为您提供出色的性能,而无需创建复杂的工程胶带。

深入研究一些示例,从count(*)开始

我们可以开始处理的最简单的查询是count(*)。对于count(*),我们需要从每个分片中获取一个count(*)。首先,针对事件表运行一个解释计划,以了解其运作方式:

QUERY PLAN ------------------------------------------------------------------------------------------------------- Aggregate (cost=0.00..0.00 rows=0 width=0) -> Custom Scan (Citus Real-Time) (cost=0.00..0.00 rows=0 width=0) Task Count: 4 Tasks Shown: One of 4 -> Task Node: host=ec2-18-233-232-9.compute-1.amazonaws.com port=5432 dbname=citus -> Aggregate (cost=11.62..11.63 rows=1 width=8) -> Seq Scan on events_102329 events (cost=0.00..11.30 rows=130 width=0) (8 rows) Time: 160.596 ms

查询中有一些注意事项。首先是它使用的是Citus Real-Time执行程序,这意味着查询正在击中所有碎片。第二个是任务是4个之一。该任务在所有节点上通常是相同的,但是由于它是纯粹的Postgres计划,可以根据数据分布和估算值进行更改。如果要查看所有查询计划,则可以扩展输出以获取所有4个分片的任务。最后,您具有针对该特定分片的查询计划本身。

让我们以集群示例为例:


如果我们要对该集群执行count(*),Citus将重新编写查询并将四个count(*)查询发送到每个分片。然后将所得的计数返回给协调器以执行最终聚合:


性能远远超过count(*)

虽然count(*)很容易看出它是如何工作的,但是您可以执行更多操作。如果要获得四个平均值并将它们平均在一起,则实际上并不会获得结果平均值。相反,对于普通的Citus将执行sum(foo)和count(foo),然后在协调器上将sum(foo)/ count(foo)相除,以得出正确的结果。最好的部分仍然可以编写AVG,Citus负责底层的复杂性。

除了汇总之外,Citus还可以告诉您何时加入并在本地执行这些加入。让我们向事件表中添加另一个表:会话。现在,对于每个事件,我们都将会话ID记录为其中的一部分,以便我们加入。有了这两个表,我们现在想要一个查询,该查询将告诉我们会话的平均事件数,以及上周创建的会话:

SELECT count(events.*),
      count(distinct session_id)
FROM events,
    sessions
WHERE sessions.created_at >= now() - '1 week'::interval
 AND sessions.id = events.session_id

在这两个表上都分配有会话ID的情况下,Citus会知道这些表在同一位置。使用共置的表,Citus将重新编写查询以将连接向下推送到本地,从而不会通过网络发送太多数据。结果是,我们将从每个分片(而不是所有原始数据)中将2条记录发送回协调器,从而大大缩短了分析查询时间。内部重写的内容可能类似于:

SELECT count(events_01.*),
      count(distinct session_id)
FROM events_01,
    sessions_01
WHERE sessions_01.created_at >= now() - '1 week'::interval
 AND sessions_01.id = events_01.session_id

SELECT count(events_02.*),
      count(distinct session_id)
FROM events_02,
    sessions_02
WHERE sessions_02.created_at >= now() - '1 week'::interval
 AND sessions_02.id = events_02.session_id

...

分布式SQL不一定很困难,但是可以肯定很快

下推连接和并行化的好处是:

  • 您不必通过网络发送太多数据,这比在内存中扫描要慢

  • 您可以一次利用系统中的所有内核,而不是在单个内核上运行查询

  • 您可以超出可以在一台计算机中装载多少内存/内核的限制

希望这次对Citus实时执行器的浏览简化了幕后工作的方式。如果您想更深入地学习,请阅读我们的文档。



©著作权归作者所有:来自51CTO博客作者mob604756f59f47的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 【PostgreSQL】PostgreSQL扩展:pg_stat_statements 优化SQL
  2. 执行 Application.Terminate 后, OnDestroy 中的代码还会执行
  3. Perl Dancer 学习(一)
  4. 使用 IntraWeb (33) - Cookie
  5. 快递批量查询教程,详细介绍如何批量查询很多快递单的方法
  6. 快递100快递查询接口(API)接口规范说明文档-详细版
  7. [源码分析] 带你梳理 Flink SQL / Table API内部执行流程
  8. [记录点滴] 小心 Hadoop Speculative 调度策略
  9. nginx开启日志,指定格式,查看执行时间

随机推荐

  1. Android Thread 介绍与实例
  2. Android: couldn't save which view has
  3. android设置Activity背景透明
  4. 抽屉类
  5. Android(安卓)中访问SDCARD
  6. Android Framework系统服务详解
  7. 转载:Android之PreferenceActivity
  8. Android 修改EditText的光标颜色和背景色
  9. android 实用代码片段整理
  10. 使用Eclipse+ADT开发android 1.5程序