2012-09-14 114 views
1

我有以下的問題在數據庫中處理大數據:MySQL的海量數據操作處理

基本上所有從數字傳感器計量被存儲在數據庫中爲每個第二。 報告應該顯示的所有數據只是發生的變化,例如在時間X寄存器#1將值從0更改爲1.

我創建了一個過程,它只能返回數據i需要(更改),並且這爲php節省了很多處理空間,但最大的問題是,對於當前4天的數據,查詢需要6 * N秒來完成,其中N是所選寄存器的數量。

現在我想知道什麼是解決這一問題的最佳解決方案。

另一個想法是:把上的數據計量的每一個新插入的觸發器,但問題是,這將是更加複雜,因爲我將需要尋找到在其他時間提交,以前的計量。

所以我想創建視圖,將新的數據以某種方式到達自動更新。這意味着當對報告進行請求時,數據將準備好並從視圖中提取。

這是一個很好的解決方案嗎?

回答

0

通過單個查詢識別您現有數據的狀態更改是可能的,但是(如您所發現的)相當昂貴。我強烈建議您將每個狀態更改存儲在緩存中。

由於@Fluffeh explained,仰視從現有的表中的最新狀態,如果你使用一個合適的指數不會很昂貴;所以觸發方法應該是相當合理的。

因此:

  1. 定義合適的索引(如果它不存在的話):

    ALTER TABLE existing_table ADD INDEX (register_id, timestamp); 
    
  2. 用於緩存創建一個表(以及可選地設置用戶權限,以便它不能請直接修改您的應用程序):

    CREATE TABLE status_changes VALUES (
        register_id ..., 
        timestamp TIMESTAMP, 
        old_status ..., 
        new_status ..., 
    
        PRIMARY KEY    (register_id, timestamp), 
    
        FOREIGN KEY    (register_id, timestamp, old_status) 
        REFERENCES existing_table (register_id, timestamp, status), 
    
        FOREIGN KEY    (register_id, timestamp, new_status) 
        REFERENCES existing_table (register_id, timestamp, status) 
    ); 
    
  3. Define

    DELIMITER ;; 
    
    CREATE TRIGGER record_change AFTER INSERT ON existing_table FOR EACH ROW 
    BEGIN 
        DECLARE _last_status ... ; 
    
        SELECT last.status 
        INTO  _last_status 
        FROM  existing_table AS last 
        WHERE last.register_id <=> NEW.register_id 
         AND last.timestamp < NEW.timestamp 
        ORDER BY last.timestamp DESC 
        LIMIT 1; 
    
        IF NOT NEW.status <=> _last_status THEN 
        INSERT INTO status_changes (
         register_id, 
         timestamp, 
         old_status, 
         new_status 
        ) VALUES (
         NEW.register_id, 
         NEW.timestamp, 
         _last_status, 
         NEW.status 
        ); 
        END IF; 
    END;; 
    
    DELIMITER ; 
    
  4. 從歷史數據填充新表:從有權修改新表用戶觸發

    INSERT IGNORE INTO status_changes (
        register_id, 
        timestamp, 
        old_status, 
        new_status 
    ) 
    SELECT NEW.register_id, 
         NEW.timestamp, 
         (
         SELECT last.status 
         FROM  existing_table AS last 
         WHERE last.register_id <=> NEW.register_id 
           AND last.timestamp < NEW.timestamp 
         ORDER BY last.timestamp DESC 
         LIMIT 1 
         ) AS _last_status, 
         NEW.status 
    FROM existing_table AS NEW 
    WHERE NOT NEW.status <=> (
         SELECT last.status 
         FROM  existing_table AS last 
         WHERE last.register_id <=> NEW.register_id 
           AND last.timestamp < NEW.timestamp 
         ORDER BY last.timestamp DESC 
         LIMIT 1 
         ) 
    ; 
    
+0

即時對不起,最後一個查詢需要什麼?我目前正致力於在表格中的每個插入之後進行狀態更改。這足以讓我在較短的時間內獲得每個寄存器的狀態更改 –

+0

@GeorgeNikolaides:我認爲您的數據庫中充滿了您希望填充新錶的歷史數據?這就是第4步所做的一切(作爲一次性練習),然後觸發器接管所有後續/新數據。 – eggyal

+0

實際上,數據庫每秒鐘都會被新的測量值(傳感器值 - 0和1)填滿,並且正如您所建議的,現在我試圖做的是在新表格中監視0和1的變化。這將增加報告和趨勢的檢索時間。 –

0

我假設你的表是很好的索引,你的查詢是很好的利用這些指標?

在這種情況下,你似乎最有可能從複合索引中獲益 - 一個關於日期和註冊。每一個索引都會有所幫助,但兩者的綜合索引都會有更多幫助。

的語法添加一個綜合指數爲:

alter table yourTableName add index yourIndexName(col1, col2); 

mysql> select * from table1; 

+---------+------+------+-------------+ 
| autonum | ID | name | metavalue | 
+---------+------+------+-------------+ 
|  1 | 1 | Rose | Drinker  | 
|  2 | 1 | Rose | Nice Person | 
|  3 | 1 | Rose | Runner  | 
|  4 | 2 | Gary | Player  | 
|  5 | 2 | Gary | Funny  | 
|  6 | 2 | Gary | NULL  | 
|  7 | 2 | Gary | Smelly  | 
+---------+------+------+-------------+ 
7 rows in set (0.01 sec) 

mysql> alter table table1 add index autoNumID(autonum, ID); 
Query OK, 0 rows affected (0.02 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

你可以看看其他的事情,正在被一個(每小時或每天等)更新彙總表。使用一個CRON或其他的東西來運行一個查詢,這個查詢會將您的數據彙總到一個更小的表格中,以便您的報告能夠正常工作。

+0

可惜我沒有使用任何指標,我認爲這是最大的問題。值從二進制值(0和1s)轉換爲單個十進制值。這意味着在數據庫中每秒鐘唯一存儲的是十進制值。 這意味着我每次獲取數據時都必須這樣做: SUBSTRING(REVERSE(LPAD(BIN('DIVALUE'),16,0))FROM'alias_offset' FOR 1) –

+0

*選擇下頜地面*哦,親愛的神聖蝙蝠俠我,我認爲我們有一個勝利者。 – Fluffeh

+0

沒有內部連接,如果這就是你所說的 –