0

假设我有下表

CREATE TABLE `entities` (
   `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
   `timestamp` TIMESTAMP NOT NULL
      DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   `data` VARCHAR(255),
   PRIMARY KEY (`id`,`timestamp`)
);

每个实体通常只能由 引用id,除了每个实体有多个修订版,由 消除歧义timestamp。我的大部分查询将选择最近的修订,只有一小部分插入新修订,而选择所有过去的修订则更少。我预计id平均每次只有大约十几个修订。

选择最新版本的最有效(就性能和存储空间而言)方法是什么?这个问题有公认的做法吗?

在我看来,有两种方法:(1)围绕一个GROUP BY

CREATE VIEW groupedEntities AS
   SELECT id, max(timestamp) AS maxt FROM entities GROUP BY id;
CREATE VIEW currentEntities AS
   SELECT a.id, data, timestamp FROM groupedEntities AS a
      INNER JOIN entities AS b ON b.id=a.id AND b.timestamp=a.maxt
      WHERE timestamp <= CURRENT_TIMESTAMP;
SELECT * FROM currentEntities WHERE id=?;

请注意,<=CURRENT_TIMESTAMP允许通过将时间戳设置为遥远的未来来“删除”实体。并且 (2) 创建一个单独的表来存储当前的修订

CREATE TABLE currentEntities (
   `id` INT(10) UNSIGNED PRIMARY KEY,
   `timestamp` TIMESTAMP,
   CONSTRAINT FOREIGN KEY (`id`, `timestamp`)
      REFERENCES `entities` (`id`,`timestamp`)
);
SELECT * FROM currentEntites INNER JOIN groupedEntities WHERE id=?;

还是其他选项(3)?

4

1 回答 1

0

由于 MySQL 处理视图的方式,视图会在性能方面吃掉你的午餐。具体来说,MySQL 为视图具体化了一个中间 MyISAM 表,并且不会将外部查询中的谓词“推送”到视图(存储或内联)中。

拥有一个单独的表来保存经常使用的“当前”修订的选项将是您提​​供的两个更好的选择。这确实增加了复杂性,使所有内容保持同步,获取当前与历史的不同查询,以及额外插入的开销等。

只给定原始表(将所有历史修订存储在与当前修订相同的表中(没有单独的表格仅用于最新修订)......

带有谓词 INSIDE 视图定义的内联视图的查询将提供最佳性能:

SELECT e.id
     , e.timestamp
     , e.data
  FROM `entities` e
  JOIN ( SELECT m.id 
              , MAX(m.timestamp) AS `timestamp`
           FROM `entities` m
          WHERE m.id = ?
          GROUP BY m.id
       ) c
     ON c.id = e.id 
    AND c.timestamp = e.timestamp

EXPLAIN 输出应Using where; Using index在具体化内联视图(派生表)的步骤上显示“”。外部查询的连接谓词是按主键,这对于检索data列是最佳的。

于 2013-11-15T01:05:12.663 回答