2011-04-22 27 views
1

我目前正在PHP構建一個腳本,它在完成它的目的時必須更新統計信息。該腳本可以通過網絡瀏覽器訪問,並且可以同時執行該流量。我必須保證統計數據是正確的。PostgreSQL增量表中的行數

爲了讓您的圖片,讓我們說我們有一個表:

CREATE TABLE statistics(
    user_id  integer NOT NULL, 
    date   integer NOT NULL, -- for unix time 
    stat1  integer NOT NULL DEFAULT 0, 
    stat2  integer NOT NULL DEFAULT 0, 
    stat3  integer NOT NULL DEFAULT 0 -- and so on... 
); 

-- Let's insert some testing data for a couple of users and days... 
-- Day one 
INSERT INTO statistics(1, 1303520820, 1, 1, 1); 
INSERT INTO statistics(2, 1303520820, 1, 1, 1); 
-- Day two 
INSERT INTO statistics(1, 1303603200, 1, 1, 1); 
INSERT INTO statistics(2, 1303603200, 1, 1, 1); 
-- Day three 
INSERT INTO statistics(1, 1303689600, 1, 1, 1); 
INSERT INTO statistics(2, 1303689600, 1, 1, 1); 

每天都有新行插入表中,所以我們可以有一個每日,每週,每月,每年的數據統計。我必須確保每個user_id每天只插入一行。同樣,無論何時執行UPDATE查詢,它都會適當地增加列stat1stat2stat3

這個腳本預計會有一些流量,我想知道如何在腳本執行時使事情有效並且有幾個實例同時工作。你覺得哪種方法/技巧最適合這樣的工作?

+1

每天一行或每行user_id每天一行?無論你想保證哪一個,「主鍵」和「唯一」都是你的朋友。 – 2011-04-22 22:33:56

+0

每個user_id每天一行。我會糾正 - 對不起,錯誤:) – tftd 2011-04-22 22:35:40

回答

3

最簡單的辦法是增加一個唯一約束

CREATE TABLE statistics(
    user_id  integer NOT NULL, 
    date   integer NOT NULL, -- for unix time 
    stat1  integer NOT NULL DEFAULT 0, 
    stat2  integer NOT NULL DEFAULT 0, 
    stat3  integer NOT NULL DEFAULT 0, -- and so on... 
    UNIQUE(user_id,date) 
); 

你一定要做到這一點,無論你採取什麼其他措施。

+0

是的,我雖然這樣。很可能我只會將UNIQUE添加到日期列中。我不能將它添加到user_id列,因爲表可以有相同的user_id無盡的行:) – tftd 2011-04-22 23:09:30

+0

第二,雖然我不能將唯一約束添加到結構。看問題中的例子。 user_id可以相同,日期可以相同。每個用戶每天都會在數據庫中獲得新記錄。 – tftd 2011-04-22 23:35:42

+2

'UNIQUE(user_id,date)'意味着user_id和date的每個組合都必須是唯一的,它與'UNIQUE(date),UNIQUE(user_id)'不同,即每個用戶每個日期只能有一行,而不是每個用戶1行和每個日期1行。 – 2011-04-23 00:16:12

1

正如其他人所說,您需要一對唯一的user_id和date對。

爲了插入而不做算術時,複合鍵(USER_ID,日期)不存在,而當複合鍵不存在算術更新,你需要編寫一些代碼。非正式地,這被稱爲「upsert」。有不止一種方法。

PosgreSQL docs有一個使用異常處理來實現這種需求的函數的例子。一個函數的問題是你不能強制應用程序代碼或數據庫女孩每次都使用它。你可以(我認爲)使用suppress_redundant_updates_trigger()。觸發器的優點是不能被應用程序代碼或數據庫女孩偶然繞過。我自己並沒有使用這種技術,所以我不能對此進行評論。這個觸發器記錄在here

您也可以handle the upsert logic with a user-defined trigger。你

1

還可以添加檢查日期值,以確保它1天的多:

ALTER TABLE "statistics" ADD CONSTRAINT "1day_quantum" CHECK ("date" = ("date"/86400)::INTEGER * 86400); 

那麼,如果一個嘗試插入日期的錯誤值會拋出異常。

如果日期字段類型爲時間戳或TIMESTAMPTZ然後檢查是比較複雜:

ALTER TABLE "statistics" ADD CONSTRAINT "1day_quantum" CHECK ("date" = TIMESTAMP 'epoch' + ((EXTRACT(EPOCH FROM "date")/86400)::INTEGER * 86400) * INTERVAL '1 second'); 

通過改變86400(秒計數)可以調整約束各種量子:900 15分鐘例如。