2017-02-12 34 views
1

我正在爲分析應用程序設計數據庫。我的數據從CSV文件加載。該文件包含一系列對稱爲'feed'的對象的double值(可能超過100k值)。雙列數組的JSON列

我想將這些double數組存儲到PostgreSQL中的JSON列中並「分區」數據。我將選擇一個因子數(例如:1000),這意味着對於每個JSON,它都包含最多1000個值。其結果是,如果你在CSV 3000個值,那麼你將有3排,每排將包含1000個值等的JSON在下面:

Table feed 
---------------------------------------- 
| id | data | 
| 1 | { data: [1,2,3,4...1000]} 
| 2 | { data: [1001,1002,...,2000]} 
| 3 | { data: [2001,2002,...,3000]} 

如果您想更新任何值,那麼我會複製每個JSON中的數組都帶有新值,其他數字將爲-1。

例如,如果你想改變值2002(在索引1)4500,則該表將是:

Table feed 
---------------------------------------- 
| id | data | 
| 1 | { data: [1,2,3,4...1000]} 
| 2 | { data: [1001,1002,...,2000]} 
| 3 | { data: [2001,2002,...,3000], new_data: [-1,4500,-1,-1...]} 

也許我會添加一些額外的元數據列描述JSON數據,作爲array_length,is_modifed ....以便於處理。

我不知道這個設計我可以輕鬆地做CRUD操作嗎?這對渲染和更新圖表是否實時很有用?因爲讀取,寫入,更新......這個數組數據是如此頻繁。有沒有人可以給我一些建議?

感謝

+0

我想知道你怎麼可能想出這樣一個人爲的方案。重點是什麼?有沒有我們不知道的原因/要求導致你這樣做? – jcaron

+0

大多數情況下,數組用於呈現圖表,並且當某人編輯圖表中的任何點時,該值將被更新,另一件事是客戶端將輪詢新數據更改以刷新圖表。所以我認爲使用JSON易於閱讀和渲染 – Barcelona

回答

3

在你的描述是一個非常糟糕的主意的情況下使用JSON數據。

JSON is a lightweight data-interchange format,因此不是特別有效作爲數據存儲數據操縱格式和PostgreSQL作爲關係數據存儲模型特別不適合或者用於JSON操縱(JSON具有分層數據結構)或大型數組。

一些更具體的原因你的想法是不高效的:

  • 推杆1000的雙精度值以陣列產量超過8000個字節(假定jsonb數據類型的數據結構:8,000字節爲雙打,一些結構本身及其描述符的開銷;常規的json很可能會更大,因爲每個值至少要有8個字符才能準確描述每個值的大小)。這意味着該表格將會是TOAST ed,這會導致性能損失。
  • 更新數組中的單個值需要重寫整個記錄(在主表和TOAST表中),而且效率極低。

在PostgreSQL中使用簡單的關係結構,用觸發器來實現你的邏輯,你會好得多。如果您的圖表客戶端希望將JSON文檔作爲輸入,那麼PostgreSQL可以即時生成。例如:

CREATE TABLE feed (
    "index" integer, 
    value  double precision 
); 

CREATE FUNCTION trf_upd_feed RETURNS trigger AS $$ 
BEGIN 
    -- This DELETE statement throws out unwanted data (the -1 values in your example) 
    -- Usually there will be very few rows (just 1?) that get deleted 
    DELETE FROM feed 
    WHERE ("index" - 1)/1000 = (NEW."index" - 1)/1000; -- integer division! 
    RETURN NEW; 
END; 
$$ LANGUAGE plpgsql; 

CREATE TRIGGER tr_feed_update 
BEFORE UPDATE ON feed 
FOR EACH ROW EXECUTE PROCEDURE trf_upd_feed(); 

當您需要爲圖表,你可以運行一個簡單的查詢來獲取數據值的切片作爲一個JSON對象中的數據:

SELECT json_build_object('data', arr) AS json_data 
FROM (
    SELECT json_agg(coalesce(feed.value, -1)) AS arr 
    FROM generate_series(1001, 2000) i(x) 
    LEFT JOIN feed ON feed."index" = i.x) sub; 

這個整體是更因爲您不需要TOAST表,並且不存儲任何意味着什麼的數據(所有-1值)。

替代

從你的描述我收到您的圖表客戶端維護自己的價值觀,然後定期輪詢的緩存數據庫中的新數據的想法。如果是這樣,你應該改變你的邏輯。更新時不要更改值(刪除記錄),而應該在圖表應用程序讀取數據時執行此操作。爲你需要的功能,而不是更新觸發器(以便刪除一個,如果你已經創建了它的話):

CREATE FUNCTION chart_data (start_idx integer, end_idx integer) RETURNS json AS $$ 
DECLARE 
    json_data json; 
BEGIN 
    SELECT json_build_object('data', arr) INTO json_data 
    FROM (
     SELECT json_agg(coalesce(feed.value, -1)) AS arr 
     FROM generate_series(start_idx, end_idx) i(x) 
     LEFT JOIN feed ON feed."index" = i.x) sub; 

    -- Data has been read, so now it can be deleted 
    DELETE FROM feed 
    WHERE "index" BETWEEN start_idx AND end_idx; 

    RETURN json_data; 
END; 
$ LANGUAGE plpgsql VOLATILE STRICT; 

,然後簡單地調用`SELECT chart_data(1001,2000);

+0

感謝您的回答,實際上我們沒有DBA,對於PostgreSQL以及PG支持JSON的程度還不甚瞭解。這個想法只是我的團隊中的一個建議。當我應該使用JSON進行存儲? – Barcelona

+0

PG具有操縱JSON文檔的功能(對於二進制'jsonb'數據類型尤其有用),但是通常你應該讓PG存儲JSON並在客戶端進行操作。 PG可以搜索(和索引)簡單的JSON文檔(即結構良好但層次不深),但通常情況下,您希望將複雜結構分解爲關係模型(一個或多個表)並獲取並生成JSON文檔,如答案中所示。 – Patrick