Оптимизированный SQL-запрос для получения даты последнего изменения информации о пользователе - PullRequest
0 голосов
/ 27 марта 2019

Я пытаюсь отобразить дату и время последнего изменения всех пользователей. Информация о пользователях распределена по нескольким таблицам (все они содержат столбец last_modified_date). Таблицы следующие. User_Details, User_Contact_Details, User_Social_Media_Details.

Моей первой мыслью было выполнить UNION ALL следующим образом.

select user.id, user.last_modified_date from 
(
(select id, last_modified_date from "User_Details" order by id)
UNION ALL
(select user_id as id, last_modified_date from "User_Contact_Details" order by id)
UNION ALL
(select user_id as id, last_modified_date from "User_Social_Media_Details" order by id)
) as user 
where user.last_modified_date is not null
order by user.id, user.last_modified_date desc

Это позволит мне отсортировать всех пользователей и даты их последнего изменения по убыванию, а затем выполнить 1-е место для каждого пользователя. Что заставило меня задуматься, является ли это правильным и оптимизированным подходом.

Любая помощь / совет очень ценится.

Ответы [ 2 ]

1 голос
/ 27 марта 2019

Если я правильно понял вопрос, вам нужна последняя дата модификации для каждого пользователя. Это сводится к проблеме (с n = 1). И они обычно решаются с помощью distinct on () в Postgres:

select distinct on (usr.id) id, last_modified_date 
from 
(
  select id, last_modified_date 
  from "User_Details" 

  UNION ALL

  select user_id as id, last_modified_date 
  from "User_Contact_Details" 

  UNION ALL

  select user_id as id, last_modified_date 
  from "User_Social_Media_Details" 
) as usr 
where last_modified_date is not null
order by id, last_modified_date desc;

В order by внутри запросов объединения на самом деле нет необходимости, если только вы не хотите предварительно фильтровать там уже идентификаторы пользователей, что может быть более эффективным:

select distinct on (usr.id) id, last_modified_date 
from 
(
  select distinct on (id) id, last_modified_date 
  from "User_Details" 
  order by id, last_modified_date desc

  UNION ALL

  select distinct on (user_id) user_id as id, last_modified_date 
  from "User_Contact_Details" 
  order by user_id, last_modified_date desc

  UNION ALL

  select distinct on (user_id) user_id as id, last_modified_date 
  from "User_Social_Media_Details" 
  order by user_id, last_modified_date desc

) as usr 
where last_modified_date is not null
order by id, last_modified_date desc;

Вам все еще нужен distinct on () во внешнем запросе, потому что один и тот же идентификатор пользователя может быть возвращен из разных ветвей UNION.


user - зарезервированное ключевое слово, избегайте его использования в качестве идентификатора. И если вы это сделаете, вы должны процитировать его "user", чтобы избежать путаницы со встроенной функцией user


Если таблица "User_Details" является «главной» таблицей, на которую ссылаются другие, и вы просто хотите получить самую последнюю дату изменения для каждого идентификатора пользователя, независимо от того, в какой таблице произошла ошибка, вы также можете использовать объединение с группой. по:

select id, 
       max(greatest(ud.last_modified_date, ucd.last_modified_date, usmd.last_modified_date)) as latest_modification
from "User_Details" ud
  left join "User_Contact_Details" ucd on ucd.user_ud = ud.id
  left join "User_Social_Media_Details"  usmd on usmd.user_id = ud.id
group by id;
0 голосов
/ 27 марта 2019

Запускать каждую таблицу независимо:

select u.id, u.last_modified_date 
from ((select id, last_modified_date 
       from "User_Details" 
       order by last_modified_date desc
       limit 1
      ) union all
      (select user_id, last_modified_date
       from "User_Contact_Details" 
       order by last_modified_date desc
       limit 1
      ) union all
      (select user_id, last_modified_date
       from "User_Media_Details" 
       order by last_modified_date desc
       limit 1
      ) 
     ) u 
order by last_modified_date desc
limit 1;

Запустив limit в подзапросах, ядро ​​базы данных возвращает только одну строку и может использовать индекс.

РЕДАКТИРОВАТЬ:

Если вам нужно это для каждого пользователя, а не всех, то используйте group by в подзапросах и внешнем запросе:

select u.id, max(u.last_modified_date) 
from ((select id, max(last_modified_date) as last_modified_date
       from "User_Details" 
       group by id
      ) union all
      (select user_id, max(last_modified_date) as last_modified_date
       from "User_Contact_Details" 
       group by user_id
      ) union all
      (select user_id, max(last_modified_date) as last_modified_date
       from "User_Media_Details" 
       group by user_id
      ) 
     ) u 
group by user_id;
...