在CockroachDB 20.1中使用横向连接进行商业分析

121 阅读5分钟

CockroachDB的20.1版本支持横向连接,这可以极大地减少得出关键业务分析所需的代码行。今天,我将带你看一个横向连接的演示,并展示你如何在CockroachDB中直接使用它们来运行分析查询。

什么是横向连接?

横向连接是一种相关的子查询,它允许数据源在同一查询中引用以前的数据源提供的列。在实践中,这可以用来迭代结果的每一行,类似于嵌套的foreach循环。我们将使用CockroachDB 20.1和我们虚构的共享汽车公司MovR来完成一个例子。

集群设置

首先,让我们用你喜欢的方法来设置CockroachDB 20.1,包括Linux、Mac或Windows的二进制文件、Docker镜像,或者直接从源代码构建。

这个例子将集中在MovR的骑行表上,它被定义为。

CREATE TABLE rides (
                  id UUID NOT NULL,
                  city VARCHAR NOT NULL,
                  vehicle_city VARCHAR NULL,
                  rider_id UUID NULL,
                  vehicle_id UUID NULL,
                  start_address VARCHAR NULL,
                  end_address VARCHAR NULL,
                  start_time TIMESTAMP NULL,
                  end_time TIMESTAMP NULL,
                  revenue DECIMAL(10,2) NULL                   
                      )

注意,我把这个表简化了一下,以防你想跟着复制粘贴这个表和后续的查询到CockroachDB。你也可以使用我们最近在博客中提到的新的CockroachDB演示功能,在不到5分钟的时间内尝试一下。

要使用CockroachDB演示(以及带有预填充数据的更复杂的骑马表),请输入以下命令。

./cockroach demo

这个命令会自动加载MovR表和数据。

show tables;

table_name
+----------------------------+
  promo_codes
  rides
  user_promo_codes
  users
  vehicle_location_histories
  vehicles
(6 rows)

MovR OKRS。一个横向连接的例子

MovR的执行团队已经为MovR设定了一些重要的目标和关键结果(OKRs)。今年的首要目标是增加使用MovR的乘客。要做到这一点,执行团队决定最重要的关键结果是降低客户第一次乘坐和第二次乘坐之间的平均时间。这是一个重要的指标,因为它有助于客户建立使用MovR的习惯,并增加客户的终身价值,这是盈利的一个关键输入。

MovR使用CockroachDB作为它的OLTP记录系统,它记录了每个用户的每次骑行。虽然我们可以通过变化数据捕获(CDC)从CockroachDB导出任何数据到面向分析的数据库,但在这种情况下,我们不需要这样做,因为我们可以在CockroachDB中使用SQL的横向连接语法直接得出这个答案。

最终,我们会有一个相当复杂的25行查询。在我们看到完整的查询之前,让我们从中间开始,然后再逐步展开。首先,我们需要计算出用户第一次乘坐MovR的时间。

SELECT
    rider_id, 
    1 AS first_ride,
    min(start_time) AS first_ride_time
  FROM rides
  GROUP BY rider_id 

这个查询找到一个给定的骑手ID的最小骑行开始时间,并将其别名为first_ride_time变量。它还通过在first_ride列中输入1或null来跟踪用户是否完成了第一次骑行。

接下来,我们需要确定客户是否进行了第二次乘车,如果是的话,确定客户在第一次乘车后多长时间进行了第二次乘车。

SELECT
  1 AS second_ride,
  start_time AS second_ride_time
FROM rides
WHERE
  rider_id = r1.rider_id AND
  start_time > first_ride_time 
ORDER BY start_time
LIMIT 1

与上面类似,我们要根据start_time来计算second_ride_time变量。但是,这一次我们要求开始时间要大于我们之前定义的第一次骑行时间的变量。这就保证了我们能得到第二个骑行时间。

总的来说,我们可以将这些查询配对到我们的大查询中。

SELECT 
  rider_id,
  first_ride,
  first_ride_time,
  second_ride,
  second_ride_time
FROM (
    --get the first ride time
 SELECT
    rider_id,
    1 AS first_ride,
    min(start_time) AS first_ride_time
  FROM rides
  GROUP BY rider_id
) r1 LEFT JOIN LATERAL (
    -- Get the second ride time 
SELECT
  1 AS second_ride,
  start_time AS second_ride_time
FROM rides
WHERE
  rider_id = r1.rider_id AND
  start_time > first_ride_time 
ORDER BY start_time
LIMIT 1
) r2 ON true

这将产生一个看起来像的表格。


	                   rider_id    | first_ride | first_ride_time                  | second_ride | second_ride_time
+--------------------------------------+------------+----------------------------------+-------------+----------------------------------+
  04553af9-dc34-461a-95fa-8c9e7123a613 |          1 | 2019-11-13 16:10:00.627167+00:00 |           1 | 2019-11-13 16:12:59.356821+00:00
  77cacc32-57dc-4f52-83a4-d50a9a65b8bd |          1 | 2019-11-13 16:06:33.618505+00:00 |           1 | 2019-11-13 16:06:37.002664+00:00
  c2c25f39-d2a0-480f-a5bb-36ec5436e34f |          1 | 2019-11-13 16:35:06.696277+00:00 |        NULL | NULL
  418c9765-4a04-4728-9f5d-981d3a6e9c5d |          1 | 2019-11-13 16:06:28.37234+00:00  |           1 | 2019-11-13 16:19:33.451015+00:00
  4be831d4-9115-412b-b2c4-dceb92c81e10 |          1 | 2019-11-13 16:15:32.557127+00:00 |           1 | 2019-11-13 16:20:33.258865+00:00

这很好,但我们可以做得更好,直接在CockroachDB中使用avg比较两个定义的变量:first_ride_time和second_ride_time,进行比较。

 SELECT 
  avg(second_ride_time::DECIMAL - first_ride_time::DECIMAL) as average_time_to_second_ride
FROM (
    --get the first ride time
 SELECT
    rider_id,
    1 AS first_ride,
    min(start_time) AS first_ride_time
  FROM rides
  GROUP BY rider_id
) r1 LEFT JOIN LATERAL (
    -- Get the second ride time 
SELECT
  1 AS second_ride,
  start_time AS second_ride_time
FROM rides
WHERE
  rider_id = r1.rider_id AND
  start_time > first_ride_time 
ORDER BY start_time
LIMIT 1
) r2 ON true

This will produce a result like: 
  average_time_to_second_ride
+-----------------------------+
        38690.915436623268698
(1 row)
 
Time: 16.576ms

*注意,如果你在家里跟着做,你可能会看到不同的最终结果,因为我们在MovR应用程序中生成随机数据。

在这种情况下,我们的骑手需要大约10个小时来完成他们的第二次骑行。现在我们有可操作的数据作为我们OKR的基线。我们可以衡量我们在降低第二次骑行时间方面所做的努力是否成功,并将其作为一个关键结果向前推进。它也可能开始提示我们一个特定的模式--MovR客户可能使用MovR上下班,平均时间约为10小时。

在CockroachDB 20.1中尝试横向连接

CockroachDB的20.1版本现在支持横向连接,这可以极大地减少得出关键业务分析所需的代码行。它为应用开发者开辟了一个全新的世界,增强了相关子查询的功能。正如我们上面所展示的,一个LEFT JOIN到LATERAL子查询可以在结果中提供源行,即使LATERAL子查询没有产生任何行。要想自己尝试横向连接,请测试一下CockroachDB 20.1!