Поиск последнего известного обновления для каждого объекта в SQL - PullRequest
0 голосов
/ 13 апреля 2020

У меня есть 2 таблицы: одна хранит объекты (Object), а другая хранит обновления состояния (например: NOT_DONE, BEING_MANUFACTURED, DONE) объектов (ObjectStateUpdate): диаграмма базы данных

Каждый раз, когда объект изменяет состояние, в таблицу ObjectStateUpdate добавляется строка с новым состоянием и датой изменения состояния.

В моем приложении есть сценарий использования, в котором я хочу получить все объекты, которые находятся в определенном состоянии c (скажем, все производимые объекты).

Это делается с помощью сложного запроса SQL, который получает последнее известное обновление для каждого объекта на основе дата обновления и, если два обновления произошли одновременно, я использую идентификатор обновлений, чтобы найти последнее (каждый объект имеет хотя бы одно обновление состояния):

SELECT * 
FROM ObjectStateUpdate 
WHERE id =
(
    SELECT MAX(id) 
    FROM ObjectStateUpdate 
    INNER JOIN (
        SELECT objectId, MAX(date) AS max_date 
        FROM trade_manager_app_orderupdate GROUP BY objectId
    ) as Latest 
    ON ObjectStateUpdate.objectId = Latest.objectId 
    AND ObjectStateUpdate.date = Latest.max_date 
    GROUP BY ObjectStateUpdate.objectId
)

Я думал добавления столбца внешнего ключа "lastUpdateId" в таблицу объектов для хранения идентификатора последнего обновления объекта (каждый раз, когда я получаю новое обновление, я сохраняю ts id объекта).

Это может избежать необходимости выполнять большой запрос SQL, заменив его гораздо более эффективным, но я боюсь, что это добавит несогласованность в модель базы данных, если для некоторых причина, по которой «lastUpdateId» не соответствует данным таблицы ObjectStateUpdate.

Так должен ли я добавить этот столбец в таблицу объектов для повышения производительности или сохранить его таким образом, чтобы избежать несоответствия?

1 Ответ

0 голосов
/ 13 апреля 2020

Если я следил за вами правильно, вы можете значительно упростить свой существующий запрос, используя row_number() (если ваша версия SQLite поддерживает их);

select *
from (
    select u.*, row_number() over(partition by objectId order by date desc, id desc) rn 
    from ObjectStateUpdate u
) t
where rn = 1 and state = 'BEING_MANUFACTURED'

Вы можете получить тот же результат с помощью коррелированного подзапроса:

Вы можете получить тот же результат с помощью коррелированного подзапроса:

select u.*
from ObjectStateUpdate u
where 
    id = (
        select u1.id
        from ObjectStateUpdate u1
        where u1.objectId = u.objectId
        order by date desc, id desc
        limit 1
    )
    and state = 'BEING_MANUFACTURED'

Для производительности вам нужен индекс на (objectId, date, id).

...