我的配置表

时间:2016-01-06 13:53:40

标签: mysql sql performance

我有一个mySQL表,它包含我的项目配置,每个配置更改都会创建一个新条目,这样我就可以记录所有更改,以及更改了哪些更改。

CREATE TABLE `configurations` (
  `name` varchar(255) NOT NULL,
  `value` text NOT NULL,
  `lastChange` datetime NOT NULL,
  `changedBy` bigint(32) NOT NULL,
  KEY `lastChange` (`lastChange`),
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

INSERT INTO `configurations` (`name`, `value`, `lastChange`, `changedBy`) VALUES
('activePageLimit', 'activePageLimit-old-value', '2016-01-06 12:25:05', 1096775260340178),
('activePageLimit', 'activePageLimit-new-value', '2016-01-06 12:27:57', 1096775260340178),
('customerLogo', 'customerLogo-old-value', '2016-02-06 00:00:00', 1096775260340178),
('customerLogo', 'customerLogo-new-value', '2016-01-07 00:00:00', 1096775260340178);

现在我的select查询有问题,应该返回所有名称及其最新值(按lastChange排序)。

|            name |                     value |                lastChange |
|-----------------|---------------------------|---------------------------|
|    customerLogo |    customerLogo-new-value | January, 07 2016 00:00:00 |
| activePageLimit | activePageLimit-new-value | January, 06 2016 12:27:57 |

我目前的查询是:

SELECT `name`, `value`, `lastChange` 
FROM (
  SELECT `name`,  `value`, `lastChange` 
  FROM `configurations` 
  ORDER BY `lastChange` ASC
) AS  `c` 
GROUP BY `name` DESC

但不幸的是,这并不总是返回正确的值,我不喜欢使用子查询,必须有一个更清洁,更快的方法来做到这一点。

我还为你创建了一个SQL-Fiddle:http://sqlfiddle.com/#!9/f1dc9/1/0

我错过了其他任何聪明的解决方案吗?

3 个答案:

答案 0 :(得分:1)

记录您的方法以返回不确定的结果(因为select中的列不在group by中)。

以下是三种选择。第一种是标准SQL,使用显式聚合来获取最新的更改。

SELECT c.*
FROM configurations c JOIN
     (SELECT `name`,  MAX(`lastChange`) as maxlc
      FROM `configurations` 
      GROUP BY name
     ) mc
     ON c.name = mc.name and c.lasthange = mc.maxlc ;

第二个也是标准SQL,使用not exists

select c.*
from configurations c
where not exists (select 1
                  from configurations c2
                  where c2.name = c.name and c2.lastchange > c.lastchange
                 );

第三个使用MySQL中可用的hack(它假定该版本中没有任何逗号,并且不会太长):

select name, max(lastchange),
       substring_index(group_concat(value order by lastchange desc), ',', 1) as value
from configurations
order by name;

请谨慎使用此版本,因为它容易出错(例如,中间group_concat()结果可能超过MySQL参数,然后必须重新设置)。

还有其他方法 - 例如使用变量。但这三个应该足以让你考虑你的选择。

答案 1 :(得分:0)

如果我们想避免SUBQUERY,唯一的另一个选择是JOIN

SELECT cc.name, cc.value, cc.lastChange FROM configurations cc
JOIN (
  SELECT name,  value, lastChange 
  FROM configurations 
  ORDER BY lastChange ASC
) c on c.value = cc.value
GROUP BY cc.name DESC

答案 2 :(得分:0)

您有两个要求:历史记录和“状态”。将它们保存在两个不同的表中,尽管提供了冗余信息。

也就是说,有一张表忠实地记录了谁在什么时候改变了什么。

有另一个表忠实地指定配置的当前状态。

计划A:INSERT进入LogUPDATE状态。

B计划:UPDATE State并使用TRIGGER写信给Log