我在处理数据库中的大数据时遇到以下问题:

基本上,每秒钟将来自数字传感器的所有计量都存储在数据库中。
报告应从所有数据中显示的只是发生的更改,例如,在时间X处寄存器1的值从0更改为1。

我创建了一个过程,该过程只能返回我需要的数据(更改),并且为我节省了很多php处理,但是最大的问题是,对于4天的当前数据,查询需要6 * N完成的秒数,其中N是所选寄存器的数量。

现在我想知道什么是克服此问题的最佳解决方案。

另一个想法是在数据计量的每个新插入上触发一个问题,但是问题是,这将变得更加复杂,因为我将需要研究在另一时间提交的先前的计量。

因此,我想创建一些视图,这些视图将在新数据以某种方式到达时自动更新。这意味着当请求报告时,数据将准备就绪并从视图中获取。

这将是一个好的解决方案吗?

最佳答案

只需一次查询就可以从现有数据中识别状态更改,但是(如您所发现的)代价很高。我敦促您将每个状态更改存储在缓存中。

作为@Fluffeh explained,如果使用合适的索引,从现有表中查找最新状态将不会很昂贵;因此触发方式应该是相当合理的。

因此:


定义一个合适的索引(如果尚不存在):

ALTER TABLE existing_table ADD INDEX (register_id, timestamp);

为缓存创建一个表(并可以选择设置用户权限,以便您的应用程序不能直接对其进行修改):

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)
);

定义来自有权修改新表的用户的触发器:

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 ;

根据历史数据填充新表:

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
       )
;

09-25 16:05
查看更多