PostgreSQL中如何使用Lateral類型

這篇文章給大家介紹PostgreSQL中如何使用Lateral類型,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

創(chuàng)新互聯(lián)建站長期為1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為李滄企業(yè)提供專業(yè)的成都網(wǎng)站制作、做網(wǎng)站,李滄網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

PostgreSQL 9.3 用了一種新的聯(lián)合類型! Lateral聯(lián)合的推出比較低調(diào),但它實現(xiàn)了之前需要使用編寫程序才能獲得的強大的新查詢. 在本文中, 我將會介紹一個在 PostgreSQL 9.2 不可能被實現(xiàn)的渠道轉(zhuǎn)換分析.
什么是 LATERAL 聯(lián)合?

對此的最佳描述在文檔中 可選 FROM 語句清單 的底部:

LATERAL 關(guān)鍵詞可以在前綴一個 SELECT FROM 子項. 這能讓 SELECT 子項在FROM項出現(xiàn)之前就引用到FROM項中的列. (沒有 LATERAL 的話, 每一個 SELECT 子項彼此都是獨立的,因此不能夠?qū)ζ渌?FROM 項進行交叉引用.)

當一個 FROM 項包含 LATERAL 交叉引用的時候,查詢的計算過程如下: 對于FROM像提供給交叉引用列的每一行,或者多個FROM像提供給引用列的行的集合, LATERAL 項都會使用行或者行的集合的列值來進行計算. 計算出來的結(jié)果集像往常一樣被加入到聯(lián)合查詢之中. 這一過程會在列的來源表的行或者行的集合上重復(fù)進行.

這種計算有一點密集。你可以比較松散的將 LATERAL 聯(lián)合理解作一個 SQL 的foreach 選擇, 在這個循環(huán)中 PostgreSQL 將循環(huán)一個結(jié)果集中的每一行,并將那一行作為參數(shù)來執(zhí)行一次子查詢的計算.

我們可以用這個來干些什么?

看看下面這個用來記錄點擊事件的表結(jié)構(gòu):
 

CREATE TABLE event (
  user_id BIGINT,
  event_id BIGINT,
  time BIGINT NOT NULL,
  data JSON NOT NULL,
  PRIMARY KEY (user_id, event_id)
)

每一個事件都關(guān)聯(lián)了一個用戶,擁有一個ID,一個時間戳,還有一個帶有事件屬性的JSON blob. 在堆中,這些屬性可能包含一次點擊的DOM層級, 窗口的標題,會話引用等等信息.

加入我們要優(yōu)化我們的登錄頁面以增加注冊. 第一步就是要計算看看我們的哪個渠道轉(zhuǎn)換上正在丟失用戶.

PostgreSQL中如何使用Lateral類型

示例:一個注冊流程的個步驟之間的渠道轉(zhuǎn)換率.


假設(shè)我們已經(jīng)在前端配備的裝置,來沿著這一流程來記錄事件日志,所有的數(shù)據(jù)都會保存到上述的事件數(shù)據(jù)表中.[1] 最開始的問題是,我們要計算有多少人查看了我們的主頁,而他們之中有百分之多少在那次查看了主頁之后的兩個星期之內(nèi)輸入了驗證信息. 如果我們使用 PostgreSQL 較老的版本, 我們可能需要使用PL/pgSQL這一PostgreSQL內(nèi)置的過程語言 來編寫一些定制的函數(shù). 而在 9.3 中, 我們就可以使用一個 lateral 聯(lián)合,只用一個搞笑的查詢就能計算出結(jié)果,不需要任何擴展或者 PL/pgSQL.

 

SELECT
user_id,
view_homepage,
view_homepage_time,
enter_credit_card,
enter_credit_card_time
FROM (
-- Get the first time each user viewed the homepage.
SELECT
user_id,
1 AS view_homepage,
min(time) AS view_homepage_time
FROM event
WHERE
data->>'type' = 'view_homepage'
GROUP BY user_id
) e1 LEFT JOIN LATERAL (
-- For each row, get the first time the user_id did the enter_credit_card
-- event, if one exists within two weeks of view_homepage_time.
SELECT
1 AS enter_credit_card,
time AS enter_credit_card_time
FROM event
WHERE
user_id = e1.user_id AND
data->>'type' = 'enter_credit_card' AND
time BETWEEN view_homepage_time AND (view_homepage_time + 1000*60*60*24*14)
ORDER BY time
LIMIT 1
) e2 ON true

沒有人會喜歡30多行的SQL查詢,所以讓我們將這些SQL分成片段來分析。第一塊是一段普通的 SQL:
 

SELECT
  user_id,
  1 AS view_homepage,
  min(time) AS view_homepage_time
FROM event
WHERE
  data->>'type' = 'view_homepage'
GROUP BY user_id

也就是要獲取到每個用戶最開始觸發(fā) view_homepage 事件的時間. 然后我們的 lateral 聯(lián)合就可以讓我們迭代結(jié)果集的每一行,并會在接下來執(zhí)行一次參數(shù)化的子查詢. 這就等同于針對結(jié)果集的每一行都要執(zhí)行一邊下面的這個查詢:
 

SELECT
  1 AS enter_credit_card,
  time AS enter_credit_card_time
FROM event
WHERE
  user_id = e1.user_id AND
  data->>'type' = 'enter_credit_card' AND
  time BETWEEN view_homepage_time AND (view_homepage_time + 1000*60*60*24*14)
ORDER BY time
LIMIT 1

例如,對于每一個用戶,要獲取他們在觸發(fā) view_homepage_time 事件后的兩星期內(nèi)觸發(fā) enter_credit_card  事件的時間. 因為這是一個lateral聯(lián)合,我們的子查詢就可以從之前的子查詢出引用到 view_homepage_time 結(jié)果集. 否則,子查詢就只能單獨執(zhí)行,而沒辦法訪問到另外一個子查詢所計算出來的結(jié)果集.

之后哦我們整個封裝成一個select,它會返回像下面這樣的東西:

user_id | view_homepage | view_homepage_time | enter_credit_card | enter_credit_card_time
---------+---------------+--------------------+-------------------+------------------------
567 | 1 | 5234567890 | 1 | 5839367890
234 | 1 | 2234567890 | |
345 | 1 | 3234567890 | |
456 | 1 | 4234567890 | |
678 | 1 | 6234567890 | |
123 | 1 | 1234567890 | |
...


因為這是一個左聯(lián)合,所以查詢結(jié)果集中會有不匹配 enter_credit_card 事件的行,只要有 view_homepage 事件就行. 如果我們匯總所有的數(shù)值列,就會得到渠道轉(zhuǎn)換的一個清晰匯總:
 

SELECT
  sum(view_homepage) AS viewed_homepage,
  sum(enter_credit_card) AS entered_credit_card
FROM (
  -- Get the first time each user viewed the homepage.
  SELECT
  user_id,
  1 AS view_homepage,
  min(time) AS view_homepage_time
  FROM event
  WHERE
  data->>'type' = 'view_homepage'
  GROUP BY user_id
) e1 LEFT JOIN LATERAL (
  -- For each (user_id, view_homepage_time) tuple, get the first time that
  -- user did the enter_credit_card event, if one exists within two weeks.
  SELECT
  1 AS enter_credit_card,
  time AS enter_credit_card_time
  FROM event
  WHERE
  user_id = e1.user_id AND
  data->>'type' = 'enter_credit_card' AND
  time BETWEEN view_homepage_time AND (view_homepage_time + 1000*60*60*24*14)
  ORDER BY time
  LIMIT 1
) e2 ON true

… 它會輸出:

 viewed_homepage | entered_credit_card
-----------------+---------------------
827 | 10


我們可以向這個渠道中填入帶有更多l(xiāng)ateral聯(lián)合的中間步驟,來得到流程中我們需要重點改進的部分. 讓我們在查看主頁和輸入驗證信息之間加入對使用示例步驟的查詢.
 

SELECT
  sum(view_homepage) AS viewed_homepage,
  sum(use_demo) AS use_demo,
  sum(enter_credit_card) AS entered_credit_card
FROM (
  -- Get the first time each user viewed the homepage.
  SELECT
  user_id,
  1 AS view_homepage,
  min(time) AS view_homepage_time
  FROM event
  WHERE
  data->>'type' = 'view_homepage'
  GROUP BY user_id
) e1 LEFT JOIN LATERAL (
  -- For each row, get the first time the user_id did the use_demo
  -- event, if one exists within one week of view_homepage_time.
  SELECT
  user_id,
  1 AS use_demo,
  time AS use_demo_time
  FROM event
  WHERE
  user_id = e1.user_id AND
  data->>'type' = 'use_demo' AND
  time BETWEEN view_homepage_time AND (view_homepage_time + 1000*60*60*24*7)
  ORDER BY time
  LIMIT 1
) e2 ON true LEFT JOIN LATERAL (
  -- For each row, get the first time the user_id did the enter_credit_card
  -- event, if one exists within one week of use_demo_time.
  SELECT
  1 AS enter_credit_card,
  time AS enter_credit_card_time
  FROM event
  WHERE
  user_id = e2.user_id AND
  data->>'type' = 'enter_credit_card' AND
  time BETWEEN use_demo_time AND (use_demo_time + 1000*60*60*24*7)
  ORDER BY time
  LIMIT 1
) e3 ON true

這樣就會輸出:

 viewed_homepage | use_demo | entered_credit_card
-----------------+----------+---------------------
827 | 220 | 86


從查看主頁到一周之內(nèi)使用demo,再到一周以內(nèi)向其輸入信用卡信息,這就向我們提供了三個步驟的通道轉(zhuǎn)換. 從此,功能強大的 PostgreSQL 使得我們可以深入分析這些數(shù)據(jù)結(jié)果集,并對我們的網(wǎng)站性能進行整體的分析. 接著我們可能會有下面這些問題要解決:

  •     使用demo是否能增加注冊的可能性?

  •     通過廣告找到我們主頁的用戶是否同來自其他渠道的用戶擁有相同的轉(zhuǎn)換率?

  •     轉(zhuǎn)換率會跟隨不同的 A/B 測試變量發(fā)生怎樣的變化?

這些問題的答案會直接影響到產(chǎn)品的改進,它們可以從 PostgreSQL 數(shù)據(jù)庫中找到答案,因為現(xiàn)在它支持 lateral 聯(lián)合.


沒有 lateral 聯(lián)合,我們就只能借助 PL/pgSQL 來做這些分析?;蛘?,如果我們的數(shù)據(jù)集很小,我們可能就不會碰這些復(fù)雜、低效的查詢. 在一項探索性數(shù)據(jù)研究使用場景下,你可能只是將數(shù)據(jù)從 PostgreSQL 里面抽取出來,并使用你所選擇的腳本語言來對其進行分析。但是其實還存在更強大的理由來用SQL表述這些問題, 特別是如果你正想要把整個全封裝到一套易于理解的UI中,并向非技術(shù)型用戶發(fā)布功能 的時候.

注意這些查詢可以被優(yōu)化,以變得更加高效. 在本例中,如果我們在 (user_id, (data->>'type'), time)上創(chuàng)建一個btree索引, 我們只用一次索引查找就能針對每一個用戶計算每一個渠道步驟. 如果你使用的是SSD,在上面做查找花費是很小的,那這就足夠了。

關(guān)于PostgreSQL中如何使用Lateral類型就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

網(wǎng)站名稱:PostgreSQL中如何使用Lateral類型
當前地址:http://muchs.cn/article36/iehgpg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標簽優(yōu)化、商城網(wǎng)站、微信公眾號、網(wǎng)站導(dǎo)航、定制網(wǎng)站搜索引擎優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站