2014-02-21 3 views
5

я первоначально написал следующееПроизводительность: В чем разница между этими двумя запросами

SELECT t1.TransactionNumber 
FROM t1 
    JOIN 
    (
      SELECT MAX(id) id 
      FROM t1 
      WHERE Period BETWEEN '01-11-2013' and '01-12-2014' 
      GROUP BY AccountNumber 
    ) t2 
     on t1.id= t2.id 

Но это было слишком медленным. Потребовалось около 20 секунд, так как испытание, я изменил его к следующему

SELECT MAX(id) AS id 
INTO #t2 
FROM t1 
WHERE Period BETWEEN '01-11-2013' and '01-12-2014' 
GROUP BY AccountNumber 

SELECT t1.id 
FROM t1 
    JOIN #t2 t2 
     ON t1.id= t2.id 

Второй запрос занял только 1 секунда, чтобы бежать. Второй запрос выполняет поиск индекса с помощью ключа PK, тогда как первый ключ выполняет сканирование.

Примечание: id является основным ключом, сгруппированным по таблице t1.

+0

У вас есть планы выполнения для обоих запросов? – slavoo

+0

Вы имели в виду это, чтобы быть самостоятельным соединением в столбце первичного ключа таблицы 't1' или есть другие таблицы? –

+0

Существуют и другие таблицы, но это не должно быть релевантным. В первом запросе, если я запускаю только сам подзапрос, это занимает около 1 секунды. Но тогда, если ваш весь запрос, он занимает более 20 секунд. Я бы подумал, что это должно было занять не более 2 секунд, поскольку он соединяется с первичным ключом. Записи возвращаются из подзапроса меньше 2000 строк. – user172839

ответ

0

Не можете ли вы разместить все свои условия в разделе «Вкл.»?

SELECT t1.id 
FROM t1 
    JOIN 
    (
      SELECT id 
      FROM t1 
      WHERE <condition> 
    ) t2 
     on t1.id = t2.id; 

превращается в

SELECT t1.id 
FROM t1 
    JOIN t1 as t2 
     ON t1.id = t2.id AND <condition> 

UPDATE:

Retrieving the last record in each group Ссылка показывает, как получить последнюю запись в группе. SQL имеет следующие

SELECT m1.* 
FROM messages m1 LEFT JOIN messages m2 
ON (m1.name = m2.name AND m1.id < m2.id) 
WHERE m2.id IS NULL; 

Вы можете использовать это, а не group by

+0

В таблице хранятся транзакции. Я получаю максимальную транзакцию для каждой учетной записи. – user172839

+0

Не могли бы вы показать в ГДЕ? – StanislavL

+0

Исходный запрос обновлен. – user172839

0

Основное различие между этими 2 запросов является то, что второй один строго запрашивая от индекса !!!

SELECT t1.TransactionNumber 
FROM t1 
JOIN 
(
     SELECT MAX(id) id 
     FROM t1 
     WHERE Period BETWEEN '01-11-2013' and '01-12-2014' 
     GROUP BY AccountNumber 
) t2 
    on t1.id= t2.id 

ли запрашивая столбец TransactionNumber так, следовательно, не может использовать undex у вас на столе, второй запрос только с использованием идентификатора. Это будет иметь огромное значение в мире.

+0

Извините, я на самом деле не написал запрос здесь правильно. Столбцы выбора для обоих запросов должны быть одинаковыми. – user172839

0

Объединяет много ресурсов, и вычисляемый результат должен снова соединяться с таблицей, поэтому это занимает много времени. Где, как при использовании временных таблиц, результат уже хранится в таблице temp, поэтому условие соединения выполняется быстрее, чем подзапросы.

1

Это предположение, но это может быть потому, что статистика первичного ключа не работает для вас. Если оптимизатор запросов думает, что вы только собираетесь вернуть 10 записей из своего внутреннего соединения, но вместо этого вы вернетесь к 100, он переполнит буфер памяти, а затем закончит работу, чтобы записать результаты подзапроса на диск. Если вы публикуете результаты плана выполнения запроса, это должно стать довольно очевидным.

0

Попробуйте:

SELECT t1.TransactionNumber t1 WHERE t1.id = (SELECT MAX(id) id FROM t1 WHERE Period BETWEEN '01-11-2013' and '01-12-2014' GROUP BY AccountNumber) 
0

Это, как правило, лучше для производительности (хотя немного больше кода) явно объявить столбцы и типы данных вместо SELECT..INTO. Это может быть быстрее:

CREATE TABLE #t2 
    (
    id INT 
    ); 
INSERT INTO #t2(id) 
VALUES 
    (
    SELECT MAX(id) 
    FROM t1 
    WHERE Period <= '01-11-2013' 
    AND Period > '01-12-2014' 
    GROUP BY AccountNumber 
    ); 
SELECT t1.id 
FROM t1 
    JOIN #t2 t2 
     ON t1.id= t2.id 
0

Разница заключается в том, что в 1-ом запросе, двигатель не знает количество результатов в t2 (который я предполагаю это относительно небольшое число по сравнению с кол-t1, но сервер SQL заранее не знаю). Итак, план выполнения начинается с t1 (зацикливание на большое количество строк). Однако во втором запросе t2 уже имеет X количество записей, которое известно для ядра перед выполнением второй части запроса. Итак, в этом запросе механизм SQL запустит выполнение с использованием t2 (SCAN t2 с его маленькой), и для каждого ключа в t2 он выполнит поиск индекса в t1.