MySQL получить максимум (первичный ключ) для каждой составной группы - PullRequest
0 голосов
/ 29 мая 2019

У меня есть вариант использования для создания версий объектов (идентифицируемых группами objectOwnerId и objectId).Я вставляю строки в таблицу 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...