Выберите последние записи на человека - PullRequest
3 голосов
/ 22 марта 2011

Мне просто интересно, если следующие два оператора SQL имеют какие-либо различия в производительности или они по сути одинаковы:

Чтобы выбрать последнюю запись супруга / супруги из таблицы spouse (person_id, spouse_id, замужем_дата).

select *
from spouse 
where (person_id, marriage_date) in ( select person_id, max(marriage_date) 
                                      from spouse  
                                      group by person_id
                                     )

select *
from spouse s1
where marriage_date = ( select max(marriage_date) 
                        from spouse s2  
                        where s1.person_id = s2.person_id  
                      )

Это распространенное требование к отчетности, например, о последней работе сотрудника, высшем образовании и т. Д. И т. Д. Я хотел бы знать, предпочитаете ли вы вышеуказанные утверждения одному из них и почему, или, если есть другие, лучше способ (с точки зрения производительности / читабельности) для выполнения этих требований «самый последний / максимальный».

Ответы [ 3 ]

3 голосов
/ 22 марта 2011

Как уже упоминалось в предыдущем ответе, вы можете использовать оконные функции SQL-сервера , чтобы добиться этого весьма неплохо.

SELECT s1.person_id, s1.marriage_date
FROM spouse s1
JOIN ( 
    SELECT 
        person_id, 
        ROW_NUMBER() OVER (PARTITION BY person_id ORDER BY marriage_date DESC) AS Priority
        FROM spouse
    ) s2
ON s2.person_id = s1.person_id AND s2.Priority = 1

В объединенном запросе мы разбиваем данные на person_id, затем применяем функцию ранжирования (ROW_NUMBER()), которая присваивает номер каждой строке в порядке убывания marriage_date. Ранжирование выполняется независимо для каждого person_id, поэтому условие соединения s2.Priority = 1 означает, что мы получаем только запись с максимальным значением marriage_date для каждого человека.

Может оказаться полезным следующее:

1 голос
/ 22 марта 2011

Для этого вы можете использовать аналитические функции:

SELECT *
  FROM (SELECT ROW_NUMBER() OVER (PARTITION BY person_id
                                   ORDER BY marriage_date DESC) AS r,
               t.*
          FROM spouse t) x
 WHERE x.r = 1

И вы можете сравнить эффективность всех запросов, посмотрев их планы выполнения.

0 голосов
/ 22 марта 2011

Ваши примеры синтаксически одинаковы.Как правило, используйте IN, когда подзапрос является наиболее ограничивающим (т.е. удаляет много записей из набора результатов), и используйте коррелированный подзапрос, когда внешний запрос является наиболее ограничивающим (т. Е. Подзапрос имеет больше записей, чем общее количество).набор результатов).

На основе статистики таблиц и предполагаемой стоимости оптимизатор запросов Oracle может переписать предложение IN в коррелированный подзапрос и наоборот.Посмотрите на планы объяснения для вашей ситуации и выберите план с наименьшей стоимостью.

...