Задача SQL-запроса, решение? - PullRequest
0 голосов
/ 01 апреля 2010

В MS SQL Server 2005 есть таблица курсов валют:

ID | CURR | ЦЕНА | ДАТА
1 | USD | 30 | 01.10.2010
3 | GBP | 45 | 07.10.2010
5 | USD | 31 | 08.10.2010
7 | GBP | 46 | 09.10.2010
9 | USD | 32 | 12.10.2010
11 | GBP | 48 | 03.10.2010

Скорость обновляется в режиме реального времени, и в таблице содержится более 1 миллиарда строк.

Нужно написать SQL-запрос, который предоставит последние курсы для каждой валюты.
Мое решение:

SELECT c.[id],c.[curr],c.[rate],c.[date]    
FROM [curr_rate] c, (SELECT curr, MAX(date) AS rate_date FROM [curr_rate] 
      GROUP BY curr) t
WHERE c.date = t.rate_date AND c.curr = t.curr
ORDER BY c.[curr] ASC

Можно ли написать запрос без подзапросов и объединений с производными таблицами?

Ответы [ 4 ]

1 голос
/ 01 апреля 2010

Ваш запрос не использует подзапрос, поэтому изменять его не нужно. Подзапрос - это запрос SELECT, который возвращает одно значение и вложен в оператор SELECT, INSERT, UPDATE или DELETE или в другой подзапрос. Подзапрос может использоваться везде, где разрешено выражение. См. Основы подзапроса

Ваш запрос использует производную таблицу, также называемую встроенным представлением, которое вы назвали "t".

Я бы начал с избавления от древнего синтаксиса соединения:

SELECT 
    c.[id],c.[curr],c.[rate],c.[date]    
    FROM [curr_rate] c
        INNER JOIN (SELECT
                        curr, MAX(date) AS rate_date
                        FROM [curr_rate] 
                        GROUP BY curr
                   ) t ON c.curr = t.curr AND c.date = t.rate_date 
    ORDER BY c.[curr] ASC

но у него будет тот же план выполнения. Вы можете просто переместить производную таблицу в CTE, но это примерно то же самое, что и производная таблица.

Запрос, вероятно, будет выполняться быстрее, если вы создадите индексированное представление для:

SELECT
    curr, MAX(date) AS rate_date
    FROM [curr_rate] 
    GROUP BY curr

с указателем на curr + MAX (дата). Если бы тогда у вас был индекс [curr_rate] .curr + date, ваш запрос имел бы лучшую производительность и был бы:

SELECT 
    c.[id],c.[curr],c.[rate],c.[date]    
    FROM [curr_rate] c
        INNER JOIN [curr_rate_max_view] t ON c.curr = t.curr AND c.date = t.rate_date 
    ORDER BY c.[curr] ASC
1 голос
/ 01 апреля 2010

Сортировка ваших индексов, вероятно, более важна, чем синтаксис SQL при настройке этого запроса.

Возможно, стоит сравнить подход подзапроса с CTE:

;WITH currCTE
AS
(
        SELECT id
               ,curr
               ,rate
               ,date
               ,ROW_NUMBER() OVER (PARTITION BY curr
                                   ORDER BY date desc
                                  ) AS rn
        FROM [curr_rate]
)
SELECT id
       ,curr
       ,rate
       ,date
FROM currCTE
WHERE rn = 1

Если для таблицы PK задано значение id и строки всегда добавляются в таблицу в порядке дат, вы можете повысить производительность, используя id в предложении ORDER BY функции ранжирования, а не в дате.

1 голос
/ 01 апреля 2010

Нет, я думаю, что нет. У вас есть индекс по CURR и дате?

0 голосов
/ 01 апреля 2010

Я не знаю, что вы можете избежать подвыбора, но вы можете избежать объединения и даже group by:

SELECT id, curr, rate, date
FROM curr_rate r
WHERE date = (
       SELECT MAX(date)
         FROM curr_rate
        WHERE curr = r.curr
      )
ORDER BY curr ASC

Я понятия не имею, как это будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...