2011-05-11 17 views
5
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 

Me preocupa el rendimiento del IN en la cláusula WHERE cuando la tabla comienza a crecer. ¿Alguien tiene una mejor estrategia para este tipo de consulta? El número de registros devueltos por la subconsulta crece mucho más lento que el número de registros en la tabla TradeLine. La tabla TradeLine en sí misma crece a una velocidad de 10 por día.Rendimiento de consulta WHERE cláusula contiene IN (subconsulta)

Gracias.

EDIT: Utilicé la idea de mover la subconsulta de WHERE a FROM. Voté por todas las respuestas que contribuyeron a esta nueva consulta.

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 
+0

No puedes invertir el orden? Ejecute la subconsulta como la consulta externa, luego la consulta externa como la subconsulta. – soandos

+0

@soandos - ¿tiene alguna idea de cómo funcionan los RDBMS? – JNK

+0

Sí, aunque no mucho. Estaba mirando como si (a) si (b) donde el ciclo externo toma más tiempo que el interno. así que invertirlos da el mismo resultado, pero más rápido – soandos

Respuesta

5

La subconsulta en la cláusula IN no depende de nada en la consulta externa. Puede moverlo con seguridad a la FROM cláusula; un constructor de plan de consulta sensato lo haría automáticamente.

Además, llamar al EXPLAIN PLAN en cualquier consulta que vaya a utilizar en producción es obligatorio. Hágalo y vea lo que el DBMS piensa del plan para esta consulta.

2

Soy fanático de las tablas temporales cuando una subconsulta comienza a mostrar un conjunto de resultados demasiado grande.

Así que su cláusula de where sólo sería

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

y #tempResults se definiría como (advertencia: la sintaxis es de la memoria, lo que significa que puede haber errores)

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

Usando una en la voluntad esencialmente te obliga a hacer un escaneo de tabla. Cuando su mesa crece, su tiempo de ejecución crece. También está ejecutando esa consulta para cada registro devuelto. Sería más fácil de usar un escalar de selección como una tabla:

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 
+2

-1 para 'El uso de una IN básicamente lo forzará a hacer una exploración de tabla'. Esto no es del todo exacto. – JNK

+1

'IN' es simplemente otro tipo de Join (una semi unión). En 'MySQL' de hecho está implementado mal y [repetidamente reevaluado como una sub consulta correlacionada fila por fila, incluso cuando no está correlacionado] (http://stackoverflow.com/questions/3417074/why-would-an-in-condition- be-slower-in-sql/3417190 # 3417190) pero no en SQL Server. Su reescritura propuesta también cambia la semántica. –

+0

No hay 't.id' en el esquema ?! –

1

tengo 2 sugerencia que puede probar:

1). USE existe ya que no es necesario obtener datos de sub consulta, así:

donde existe (seleccione 1 de Tradeline AS TradeLine_1 donde TradeLine.Id = TradeLine_1.PairOffId - continuar con su sub consulta .. .)

2). consulta principal unirse a su subconsulta, por ejemplo

... join (your_subquery) en your_subquery.PairOffId = TradeLine.Id

Creo que estas 2 formas pueden lograr un mejor rendimiento que "En" operación.

1

He enfrentado el mismo problema con cientos de miles de registros en XXXXXX DB. En mi código quiero recuperar nodos de jerarquía (nodo que contiene al menos un elemento secundario) de todos los nodos.

enter image description here

La consulta inicial por escrito que es muy lento.

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 
    ); 

A continuación, re-escrito a

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; 
Cuestiones relacionadas