Производительность запроса Предложение WHERE содержит IN (подзапрос) - PullRequest
5 голосов
/ 12 мая 2011
SELECT Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate, 
       SUM(TradeLine.Notional) / 1000 AS Expr1
FROM   Trade INNER JOIN
             TradeLine ON Trade.TradeId = TradeLine.TradeId
WHERE  (TradeLine.Id IN
                      (SELECT     PairOffId
                        FROM          TradeLine AS TradeLine_1
                        WHERE      (TradeDate <= '2011-05-11')
                        GROUP BY PairOffId
                        HAVING      (SUM(Notional) <> 0)))
GROUP BY Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate
ORDER BY Trade.Type, Trade.TradeDate

Меня беспокоит производительность IN в предложении WHERE, когда таблица начинает расти.У кого-нибудь есть лучшая стратегия для такого рода запросов?Количество записей, возвращаемых подзапросом, растет намного медленнее, чем количество записей в таблице TradeLine.Сам стол TradeLine растет со скоростью 10 в день.

Спасибо.

РЕДАКТИРОВАТЬ: Я использовал идею перемещения подзапроса от ГДЕ к ИЗ.Я проголосовал за все ответы, которые способствовали этому новому запросу.

   SELECT Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate,   
          PairOff.Notional / 1000 AS Expr1
   FROM         Trade INNER JOIN
                  TradeLine ON Trade.TradeId = TradeLine.TradeId INNER JOIN
                      (SELECT     PairOffId, SUM(Notional) AS Notional
                        FROM          TradeLine AS TradeLine_1
                        WHERE      (TradeDate <= '2011-05-11')
                        GROUP BY PairOffId
                   HAVING (SUM(Notional) <> 0)) AS PairOff ON TradeLine.Id = PairOff.PairOffId
   ORDER BY Trade.Type, Trade.TradeDate

Ответы [ 5 ]

6 голосов
/ 12 мая 2011

Подзапрос в предложении IN не зависит ни от чего во внешнем запросе. Вы можете безопасно переместить его в предложение FROM; вменяемый построитель плана запросов сделает это автоматически.

Кроме того, вызов EXPLAIN PLAN для любого запроса, который вы собираетесь использовать в работе, является обязательным. Сделайте это и посмотрите, что СУБД думает о плане для этого запроса.

2 голосов
/ 12 мая 2011

Я фанат временных таблиц, когда подзапрос начинает возвращать слишком большой набор результатов.

Так что ваше предложение where будет просто

Where TradeLine.Id In (Select PairOffId From #tempResults)

и #tempResults будет определено как (предупреждение: синтаксис из памяти, что означает, что могут быть ошибки)

Select PairOffId Into #tempResults
From TradeLine
Where (TradeDate <= @TradeDate) 
  //I prefer params in case the query becomes a StoredProc
Group By PairOffId
Having (Sum(Notional) <> 0)
1 голос
/ 09 декабря 2015

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

enter image description here

Первоначальный написанный запрос,медленно.

  SELECT SUPPLIER_ID, PARENT_SUPPLIER_ID,
  FROM SUPPLIER
  WHERE 
    SUPPLIER_ID != PARENT_SUPPLIER_ID
    OR 
    SUPPLIER_ID   IN
      (SELECT DISTINCT PARENT_SUPPLIER_ID
       FROM SUPPLIER
       WHERE SUPPLIER_ID != PARENT_SUPPLIER_ID
      );

Затем переписывается в

  SELECT a.SUPPLIER_ID, a.PARENT_SUPPLIER_ID,
  FROM SUPPLIER a
  LEFT JOIN
  (SELECT DISTINCT PARENT_SUPPLIER_ID
  FROM SUPPLIER
  WHERE SUPPLIER_ID != PARENT_SUPPLIER_ID
  ) b
  ON a. SUPPLIER_ID     = b.PARENT_SUPPLIER_ID
  WHERE a. SUPPLIER_ID != a.PARENT_SUPPLIER_ID
     OR a. SUPPLIER_ID     = b.PARENT_SUPPLIER_ID;
1 голос
/ 12 мая 2011

У меня есть 2 предложения, которые вы можете попробовать:

1).используйте Exists, поскольку вам не нужно получать данные из подзапроса, например:

там, где существует (выберите 1 из TradeLine AS TradeLine_1, где TradeLine.Id = TradeLine_1.PairOffId - продолжить работу с вашим подзапросом ...)

2).основной запрос присоединиться к вашему подзапросу, например

... присоединиться (your_subquery) к your_subquery.PairOffId = TradeLine.Id

Я считаю, что эти 2 способа могут достичь лучшегопроизводительность, чем "В" операции.

0 голосов
/ 12 мая 2011

Использование IN по существу заставит вас сделать сканирование таблицы.Когда ваша таблица растет, время выполнения увеличивается.Также вы выполняете этот запрос для каждой возвращаемой записи.Было бы проще использовать скалярный выбор в качестве таблицы:

SELECT t.TradeId, t.Type, t.Symbol, t.TradeDate, 
       SUM(TradeLine.Notional) / 1000 AS Expr1
FROM   Trade t,
(SELECT     TradeId, PairOffID
                        FROM          TradeLine AS TradeLine_1
                        WHERE      (TradeDate <= '2011-05-11')
                        GROUP BY PairOffId
                        HAVING      (SUM(Notional) <> 0)) tl       
WHERE  t.TradeId = tl.TradeId
  and  t.id <> tl.PairOffID
GROUP BY Trade.TradeId, Trade.Type, Trade.Symbol, Trade.TradeDate
ORDER BY Trade.Type, Trade.TradeDate
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...