MySQL为每个复合组获取max(PRIMARY KEY)

时间:2019-05-29 11:59:12

标签: mysql group-by

我有用例来版本化对象(由objectOwnerIdobjectId组标识)。我将带有各自哈希值的行插入ledger表中。 ledger表的顺序由复合PRIMARY KEY及其timestamp标识,精度高达微秒,并在末尾附加了3字节的熵,以防止冲突(如果在同一微秒处插入多行) )。

一旦存储了数据,我需要一种有效的方法来一次获取多个对象的最新哈希值。我想出了一个查询(请参阅本文的结尾),该查询是通过JOIN和GROUP BY的子选择构建的,但是我认为它非常复杂,我正在寻找更简单的方法来解决我的问题(如果可能)方式。

有什么改进的方法吗?

如果我的PRIMARY KEY不是COMPOUND,那会更简单,在这种情况下,我可以向上传递max()值,但是事实并非如此。我也在考虑是否可以将TIMESTAMP(6)-7个字节与BINARY(3)-3个字节合并,并将其存储为BINARY(10),但不确定是否很容易。

请在下面找到架构,测试数据和SELECT查询。

这是我的桌子:

CREATE TABLE `ledger` (
  `objectOwnerId` CHAR(10) NOT NULL,
  `objectId` VARCHAR(50) NOT NULL,
  `objectHash` BINARY(16) NOT NULL,
  `timestamp` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
  `timestampAdditionalEntropy` BINARY(3) NOT NULL,
  PRIMARY KEY (`timestamp`, `timestampAdditionalEntropy`),
  UNIQUE(`objectHash`),
  INDEX(`objectId`(10))
);

让我们插入一些值:

INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaaa', 'ida', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaaa', 'ida', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));

INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaab', 'idb', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaab', 'idb', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));
INSERT INTO ledger (objectOwnerId, objectId, objectHash, timestampAdditionalEntropy) VALUES ('owneraaaab', 'idb', unhex(substring(sha1(random_bytes(16)), 1, 32)), random_bytes(3));

我们有这个数据集:

# objectOwnerId, objectId, objectHash, timestamp, HEX(CAST(timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))
#'owneraaaab', 'idb', 'A8D3B63EFC6C63FD996B8D1931FBF748', '2019-05-29 11:38:12.353521', '725E3D'
#'owneraaaab', 'idb', '9B7395F9EE2F2363BA89C7FBAEDDBB54', '2019-05-29 11:38:12.352524', '8B8162'
#'owneraaaab', 'idb', '80393C5FF4492342D073B5F8B3388EC2', '2019-05-29 11:38:12.351569', 'FEAA02'
#'owneraaaaa', 'ida', '0D84F725ACAC87838C34742CA00BBEF7', '2019-05-29 11:38:12.350648', '41E425'
#'owneraaaaa', 'ida', '9A82C936A25C4648BFB75B692850841B', '2019-05-29 11:38:12.349625', '470685'

此查询返回的值:

select objectOwnerId, objectId, HEX(CAST(objectHash AS CHAR(32) CHARACTER SET utf8)) as objectHash, timestamp, HEX(CAST(timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))
from ledger
order by timestamp desc, timestampAdditionalEntropy desc;

我需要得到这个:

# objectOwnerId, objectId, objectHash, timestamp, HEX(CAST(s.timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))
#owneraaaaa, ida, 0D84F725ACAC87838C34742CA00BBEF7, 2019-05-29 11:38:12.350648, 41E425
#owneraaaab, idb, A8D3B63EFC6C63FD996B8D1931FBF748, 2019-05-29 11:38:12.353521, 725E3D

此查询可以返回的内容:

select s.objectOwnerId, s.objectId, HEX(CAST(objectHash AS CHAR(32) CHARACTER SET utf8)) as objectHash, s.timestamp, HEX(CAST(s.timestampAdditionalEntropy AS CHAR(6) CHARACTER SET utf8))   from (
    select s.objectOwnerId, s.objectId, s.timestamp, max(i.timestampAdditionalEntropy) as timestampAdditionalEntropy from (
        select objectOwnerId, objectId, max(timestamp) as timestamp
        from ledger where ((objectOwnerId = 'owneraaaaa' AND objectId = 'ida') OR (objectOwnerId = 'owneraaaab' AND objectId = 'idb'))
        group by objectOwnerId, objectId    
    ) s
    JOIN ledger i on i.objectOwnerId = s.objectOwnerId and i.objectId = s.objectId and i.timestamp = s.timestamp
    group by objectOwnerId, objectId, timestamp
) s
JOIN ledger i on i.objectOwnerId = s.objectOwnerId and i.objectId = s.objectId and i.timestamp = s.timestamp and i.timestampAdditionalEntropy = s.timestampAdditionalEntropy

0 个答案:

没有答案