亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > PostgreSQL > 正文

在PostgreSQL中使用數組時值得注意的一些地方

2020-03-12 23:53:51
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了在PostgreSQL中使用數組時值得注意的一些地方,包括如何提高輸入性能,需要的朋友可以參考下

在Heap中,我們依靠PostgreSQL支撐大多數后端繁重的任務,我們存儲每個事件為一個hstoreblob,我們為每個跟蹤的用戶維護一個已完成事件的PostgreSQL數組,并將這些事件按時間排序。 Hstore能夠讓我們以靈活的方式附加屬性到事件中,而且事件數組賦予了我們強大的性能,特別是對于漏斗查詢,在這些查詢中我們計算不同轉化渠道步驟間的輸出。

在這篇文章中,我們看看那些意外接受大量輸入的PostgreSQL函數,然后以高效,慣用的方式重寫它。

你的第一反應可能是將PostgreSQL中的數組看做像C語言中對等的類似物。你之前可能用過變換陣列位置或切片來操縱數據。不過要小心,在PostgreSQL中不要有這樣的想法,特別是數組類型是變長的時,比如JSON、文本或是hstore。如果你通過位置來訪問PostgreSQL數組,你會進入一個意想不到的性能暴跌的境地。

這種情況幾星期前在Heap出現了。我們在Heap為每個跟蹤用戶維護一個事件數組,在這個數組中我們用一個hstore datum代表每個事件。我們有一個導入管道來追加新事件到對應的數組。為了使這一導入管道是冪等的,我們給每個事件設定一個event_id,我們通過一個功能函數重復運行我們的事件數組。如果我們要更新附加到事件的屬性的話,我們只需使用相同的event_id轉儲一個新的事件到管道中。

所以,我們需要一個功能函數來處理hstores數組,并且,如果兩個事件具有相同的event_id時應該使用數組中最近出現的那個。剛開始嘗試這個函數是這樣寫的:

 

 
  1. -- This is slow, and you don't want to use it! 
  2. -- 
  3. -- Filter an array of events such that there is only one event with each event_id. 
  4. -- When more than one event with the same event_id is present, take the latest one. 
  5. CREATE OR REPLACE FUNCTION dedupe_events_1(events HSTORE[]) RETURNS HSTORE[] AS $ 
  6. SELECT array_agg(event) 
  7. FROM ( 
  8. -- Filter for rank = 1, i.e. select the latest event for any collisions on event_id. 
  9. SELECT event 
  10. FROM ( 
  11. -- Rank elements with the same event_id by position in the array, descending. 

這個查詢在擁有2.4GHz的i7CPU及16GB Ram的macbook pro上測得,運行腳本為:https://gist.github.com/drob/9180760。

在這邊究竟發生了什么呢? 關鍵在于PostgreSQL存貯了一個系列的hstores作為數組的值, 而不是指向值的指針. 一個包含了三個hstores的數組看起來像

 

 
  1. {“event_id=>1,data=>foo”, “event_id=>2,data=>bar”, “event_id=>3,data=>baz”} 

相反的是

 

 
  1. {[pointer], [pointer], [pointer]} 

對于那些長度不一的變量, 舉個例子. hstores, json blobs, varchars,或者是 text fields, PostgreSQL 必須去找到每一個變量的長度. 對于evaluateevents[2], PostgreSQL 解析從左側讀取的事件直到讀取到第二次讀取的數據. 然后就是 forevents[3], 她再一次的從第一個索引處開始掃描,直到讀到第三次的數據! 所以, evaluatingevents[sub]是 O(sub), 并且 evaluatingevents[sub]對于在數組中的每一個索引都是 O(N2), N是數組的長度.

PostgreSQL能得到更加恰當的解析結果, 它可以在這樣的情況下分析該數組一次. 真正的答案是可變長度的元素與指針來實現,以數組的值, 以至于,我們總能夠處理 evaluateevents[i]在不變的時間內.

即便如此,我們也不應該讓PostgreSQL來處理,因為這不是一個地道的查詢。除了generate_subscripts我們可以用unnest,它解析數組并返回一組條目。這樣一來,我們就不需要在數組中顯式加入索引了。

 

 
  1. -- Filter an array of events such that there is only one event with each event_id. 
  2. -- When more than one event with the same event_id, is present, take the latest one. 
  3. CREATE OR REPLACE FUNCTION dedupe_events_2(events HSTORE[]) RETURNS HSTORE[] AS $ 
  4. SELECT array_agg(event) 
  5. FROM ( 
  6. -- Filter for rank = 1, i.e. select the latest event for any collisions on event_id. 
  7. SELECT event 
  8. FROM ( 
  9. -- Rank elements with the same event_id by position in the array, descending. 
  10. SELECT event, row_number AS index, rank() 
  11. OVER (PARTITION BY (event -> 'event_id')::BIGINT ORDER BY row_number DESC) 
  12. FROM ( 
  13. -- Use unnest instead of generate_subscripts to turn an array into a set. 
  14. SELECT event, row_number() 
  15. OVER (ORDER BY event -> 'time'
  16. FROM unnest(events) AS event 
  17. ) unnested_data 
  18. ) deduped_events 
  19. WHERE rank = 1 
  20. ORDER BY index ASC 
  21. ) to_agg; 
  22. $ LANGUAGE SQL IMMUTABLE; 

結果是有效的,它花費的時間跟輸入數組的大小呈線性關系。對于100K個元素的輸入它需要大約半秒,而之前的實現需要40秒。

這實現了我們的需求:

一次解析數組,不需要unnest。

按event_id劃分。

對每個event_id采用最新出現的。

按輸入索引排序。

教訓:如果你需要訪問PostgreSQL數組的特定位置,考慮使用unnest代替。

 

 
  1. SELECT events[sub] AS event, sub, rank() 
  2. OVER (PARTITION BY (events[sub] -> 'event_id')::BIGINT ORDER BY sub DESC) 
  3. FROM generate_subscripts(events, 1) AS sub 
  4. ) deduped_events 
  5. WHERE rank = 1 
  6. ORDER BY sub ASC 
  7. ) to_agg; 
  8. $ LANGUAGE SQL IMMUTABLE; 

這樣奏效,但大輸入是性能下降了。這是二次的,在輸入數組有100K各元素時它需要大約40秒!

在PostgreSQL中使用數組時值得注意的一些地方

這個查詢在擁有2.4GHz的i7CPU及16GB Ram的macbook pro上測得,運行腳本為:https://gist.github.com/drob/9180760。

在這邊究竟發生了什么呢? 關鍵在于PostgreSQL存貯了一個系列的hstores作為數組的值, 而不是指向值的指針. 一個包含了三個hstores的數組看起來像

 

 
  1. {“event_id=>1,data=>foo”, “event_id=>2,data=>bar”, “event_id=>3,data=>baz”} 

相反的是

 

 
  1. {[pointer], [pointer], [pointer]} 

對于那些長度不一的變量, 舉個例子. hstores, json blobs, varchars,或者是 text fields, PostgreSQL 必須去找到每一個變量的長度. 對于evaluateevents[2], PostgreSQL 解析從左側讀取的事件直到讀取到第二次讀取的數據. 然后就是 forevents[3], 她再一次的從第一個索引處開始掃描,直到讀到第三次的數據! 所以, evaluatingevents[sub]是 O(sub), 并且 evaluatingevents[sub]對于在數組中的每一個索引都是 O(N2), N是數組的長度.

PostgreSQL能得到更加恰當的解析結果, 它可以在這樣的情況下分析該數組一次. 真正的答案是可變長度的元素與指針來實現,以數組的值, 以至于,我們總能夠處理 evaluateevents[i]在不變的時間內.

即便如此,我們也不應該讓PostgreSQL來處理,因為這不是一個地道的查詢。除了generate_subscripts我們可以用unnest,它解析數組并返回一組條目。這樣一來,我們就不需要在數組中顯式加入索引了。

 

 
  1. -- Filter an array of events such that there is only one event with each event_id. 
  2. -- When more than one event with the same event_id, is present, take the latest one. 
  3. CREATE OR REPLACE FUNCTION dedupe_events_2(events HSTORE[]) RETURNS HSTORE[] AS $ 
  4. SELECT array_agg(event) 
  5. FROM ( 
  6. -- Filter for rank = 1, i.e. select the latest event for any collisions on event_id. 
  7. SELECT event 
  8. FROM ( 
  9. -- Rank elements with the same event_id by position in the array, descending. 
  10. SELECT event, row_number AS index, rank() 
  11. OVER (PARTITION BY (event -> 'event_id')::BIGINT ORDER BY row_number DESC) 
  12. FROM ( 
  13. -- Use unnest instead of generate_subscripts to turn an array into a set. 
  14. SELECT event, row_number() 
  15. OVER (ORDER BY event -> 'time'
  16. FROM unnest(events) AS event 
  17. ) unnested_data 
  18. ) deduped_events 
  19. WHERE rank = 1 
  20. ORDER BY index ASC 
  21. ) to_agg; 
  22. $ LANGUAGE SQL IMMUTABLE; 

結果是有效的,它花費的時間跟輸入數組的大小呈線性關系。對于100K個元素的輸入它需要大約半秒,而之前的實現需要40秒。

這實現了我們的需求:

一次解析數組,不需要unnest。

按event_id劃分。

對每個event_id采用最新出現的。

按輸入索引排序。

教訓:如果你需要訪問PostgreSQL數組的特定位置,考慮使用unnest代替。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美午夜性色大片在线观看| 欧美日韩在线视频一区二区| 国产精品丝袜白浆摸在线| 亚洲在线观看视频| 欧美激情乱人伦| 日韩亚洲欧美中文在线| 国产成人激情小视频| 久久久久久久久久av| 狠狠久久五月精品中文字幕| 日韩美女视频在线观看| 欧美多人乱p欧美4p久久| 国产成人综合亚洲| 国产午夜精品久久久| 亚洲男女性事视频| 欧美国产精品va在线观看| 国产精品福利在线观看网址| 国产精品第一区| 欧美午夜片在线免费观看| 精品香蕉在线观看视频一| 久久久久久久亚洲精品| 日韩在线资源网| 久久青草精品视频免费观看| 欧美成人精品在线| 精品中文字幕在线2019| 欧美与欧洲交xxxx免费观看| 最近的2019中文字幕免费一页| 亚洲成人av中文字幕| 久久久久亚洲精品国产| 欧美中文字幕视频在线观看| 国产91精品黑色丝袜高跟鞋| 日本韩国欧美精品大片卡二| 亚洲免费一级电影| 亚洲欧美另类国产| 综合网日日天干夜夜久久| 亚洲国产成人久久| 国产精品18久久久久久首页狼| 热99久久精品| 一区二区欧美久久| 欧美午夜激情小视频| 久久久久久久香蕉网| 91丝袜美腿美女视频网站| 国产日韩欧美中文| 亚洲第一精品久久忘忧草社区| 91在线无精精品一区二区| 91在线高清视频| 国产精品永久免费视频| 亚洲成av人影院在线观看| 久久久精品国产亚洲| 精品国产老师黑色丝袜高跟鞋| 韩剧1988在线观看免费完整版| 欧美电影在线播放| 国产性猛交xxxx免费看久久| 国产一区二区三区在线免费观看| 国产精品极品在线| 亚洲天堂色网站| 亚洲国产日韩欧美在线图片| 国产91网红主播在线观看| 欧美激情视频网址| 久久国产精品久久久久久久久久| 成人天堂噜噜噜| 中文字幕亚洲无线码a| 国产精品久久77777| 欧美精品久久久久久久久久| 国产亚洲人成网站在线观看| 情事1991在线| 欧美日韩精品在线视频| 91久久国产婷婷一区二区| 亚洲一区美女视频在线观看免费| 91精品视频网站| 亚洲最新av在线| 久久国产精品影片| 亚洲欧美国产va在线影院| 精品国产乱码久久久久酒店| 伊人男人综合视频网| 欧美一二三视频| 色诱女教师一区二区三区| 国产精品视频免费在线| 九色成人免费视频| 国产专区欧美专区| 久久久这里只有精品视频| 久久色精品视频| 欧美大胆a视频| 国产精品福利观看| 欧美成人激情视频| 成人美女免费网站视频| 亚洲www视频| 性色av一区二区咪爱| 亚洲第一福利在线观看| 91大神在线播放精品| 疯狂欧美牲乱大交777| 欧美亚洲伦理www| 成人午夜在线影院| 国产精品一区二区三区在线播放| 久久久午夜视频| 日本一区二区不卡| 久久久久久久久网站| 日韩一区在线视频| 久久免费国产视频| 亚洲伊人久久大香线蕉av| 久久久久久综合网天天| 久久精品国产清自在天天线| 国产精品免费久久久久久| yw.139尤物在线精品视频| 欧美久久精品一级黑人c片| 色哟哟亚洲精品一区二区| 亚洲精品久久视频| 欧美与黑人午夜性猛交久久久| 91精品一区二区| 久久亚洲精品一区二区| 精品美女久久久久久免费| 68精品国产免费久久久久久婷婷| 精品国产欧美成人夜夜嗨| 日韩中文综合网| 91欧美精品成人综合在线观看| 久久久久久久久国产| 亚洲成人精品视频在线观看| 91经典在线视频| 久久久久久久久久婷婷| 91亚洲国产精品| 亚洲高清久久网| xvideos亚洲人网站| 日韩成人av网| 中文字幕亚洲一区二区三区五十路| 国产精品高潮呻吟久久av无限| 亚洲国产日韩欧美在线99| 欧美国产激情18| 久久视频免费在线播放| 欧美精品在线第一页| 91精品国产91久久| 日韩视频中文字幕| 91精品国产91久久久久久| 欧美第一黄网免费网站| 日韩精品丝袜在线| 丝袜情趣国产精品| 欧美诱惑福利视频| 欧美性猛交xxxxx水多| 欧美成人第一页| 少妇高潮久久77777| 亚洲一区二区久久久久久| 国产丝袜一区二区三区免费视频| 欧美一级淫片videoshd| 欧美日本精品在线| 亚洲高清久久久久久| 91精品啪在线观看麻豆免费| 96pao国产成视频永久免费| 亚洲精品永久免费| 亚洲娇小xxxx欧美娇小| 国产精品麻豆va在线播放| 亚洲欧美中文另类| 精品国产鲁一鲁一区二区张丽| 国产精品男人的天堂| 欧美第一黄网免费网站| 日韩精品欧美国产精品忘忧草| 久久免费视频网站| 一区二区成人精品| 韩国三级电影久久久久久| 久久久久久久亚洲精品| 亚洲999一在线观看www| 亚洲精品不卡在线| 久久久亚洲网站| 日韩中文字幕第一页| 国产精品成人观看视频国产奇米| 国内精品久久影院| 久久亚洲综合国产精品99麻豆精品福利|