2010-10-21 24 views
13

Aquí está mi problema, estoy seleccionando y haciendo varias combinaciones para obtener los elementos correctos ... atrae una buena cantidad de filas, por encima de 100.000. Esta consulta lleva más de 5 minutos cuando el rango de fechas se establece en 1 año.¿Cómo puedo acelerar la consulta de MySQL con varias combinaciones?

No sé si es posible, pero me temo que el usuario podría extender el intervalo de fechas a diez años y bloquearlo.

¿Alguien sabe cómo puedo acelerar esto? Aquí está la consulta.

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM table1 AS t1 
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id 
WHERE t1.subscribe =1 
AND t1.Cdate >= $startDate 
AND t1.Cdate <= $endDate 
AND t5.store =2 

¡No soy el mejor con mysql así que cualquier ayuda sería apreciada!

¡Gracias de antemano!

ACTUALIZACIÓN

Aquí se explica el que pidió

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE t5 ref  PRIMARY,C_store_type,C_id,C_store_type_2 C_store_type_2 1 const 101  Using temporary 
1 SIMPLE t4 ref  PRIMARY,P_cat P_cat 5 alphacom.t5.C_id 326  Using where 
1 SIMPLE t3 ref  I_pid,I_oref I_pid 4 alphacom.t4.P_id 31 
1 SIMPLE t2 eq_ref O_ref,O_cid  O_ref 28 alphacom.t3.I_oref 1  
1 SIMPLE t1 eq_ref PRIMARY  PRIMARY  4 alphacom.t2.O_cid 1 Using where 

También he añadido un índice para Tabla5 filas y filas Table4 porque realmente no cambian, sin embargo las otras mesas conseguir alrededor 500-1000 entradas al mes ... Escuché que debería agregar un índice a una tabla que tenga tantas entradas nuevas ... ¿es cierto?

+3

Sería útil conocer las tablas y la indexación en su lugar: actualice para incluir las instrucciones CREATE TABLE. La necesidad de 'DISTINCT' hace que me pregunte qué tabla (s) son responsables de necesitar eso. –

+0

Un EXPLAIN ayudaría también. – ceejayoz

+0

-OMG Ponies, no sé a qué te refieres con las sentencias create table. -Ceejayoz, agregué el EXPLAIN – BinarySolo00100

Respuesta

10

que iba a tratar lo siguiente:

en primer lugar, asegurarse de que no índices en las siguientes tablas y columnas (cada conjunto de columnas entre paréntesis debe ser un índice separado):

table1 : (subscribe, CDate) 
     (CU_id) 
table2 : (O_cid) 
     (O_ref) 
table3 : (I_oref) 
     (I_pid) 
table4 : (P_id) 
     (P_cat) 
table5 : (C_id, store) 

En segundo lugar, si la adición de los índices anteriores no mejoró las cosas tanto como desee, intente volver a escribir la consulta como

SELECT DISTINCT t1.first_name, t1.last_name, t1.email FROM 
    (SELECT CU_id, t1.first_name, t1.last_name, t1.email 
    FROM table1 
    WHERE subscribe = 1 AND 
      CDate >= $startDate AND 
      CDate <= $endDate) AS t1 
    INNER JOIN table2 AS t2 
    ON t1.CU_id = t2.O_cid 
    INNER JOIN table3 AS t3 
    ON t2.O_ref = t3.I_oref 
    INNER JOIN table4 AS t4 
    ON t3.I_pid = t4.P_id 
    INNER JOIN (SELECT C_id FROM table5 WHERE store = 2) AS t5 
    ON t4.P_cat = t5.C_id 

estoy esperando aquí que el primer sub -seleccionar reduciría significativamente el número de filas que se considerarán para unirse, con suerte las uniones posteriores harán menos trabajo. Lo mismo ocurre con el razonamiento detrás de la segunda sub-selección en la tabla5.

En cualquier caso, lío con él. Quiero decir, en última instancia, es solo un SELECTO, realmente no puedes herir nada con eso. Examine los planes que se generan con cada permutación diferente y trate de descubrir qué es bueno o malo para cada uno.

Comparte y disfruta.

+0

Gracias, creo que esto ayudará, voy a perder el tiempo. No tengo mucha experiencia en MySQL o en material de base de datos en general, así que realmente aprecio tu ayuda. Además, actualicé la pregunta, no agregué un índice a algunas de las tablas porque no estaba seguro de si debería, ya que hay alrededor de 500-1000 nuevas filas agregadas cada mes. – BinarySolo00100

+1

Terminé usando esto y causó un gran impacto ENORME, ¡gracias! – BinarySolo00100

+1

@ BinarySolo00100 - me alegro de haberlo ayudado. En cuanto a la adición de índices, supongo que le preocupa que la indexación general pueda ralentizar las inserciones y actualizaciones. Mi experiencia es que, por alguna razón, las personas (especialmente los DBA) están demasiado preocupadas por la indexación y terminan con un rendimiento SELECT pobre debido a eso. Creo que este es un caso de optimización prematura, es decir, preocupación por un problema potencial inexistente. Hasta que tenga un problema mensurable, no tiene problema. Agregue los índices (o lo que sea) y MEDICIÓN, MEDIDA, MEDIDA - luego actúe según esa información. –

8

Asegúrate de que las columnas de fecha y todas las columnas a las que te estás uniendo estén indexadas.

Hacer un operador de desigualdad en sus fechas significa que comprueba cada fila, que es intrínsecamente más lenta que una equivalencia.

Además, el uso de DISTINCT añade una comparación extra a la lógica de que su optimizador se ejecuta detrás de las escenas. Eliminar eso si es posible.

-1

Parece que debe pensar en entregar subconjuntos (paginación) o limitar los resultados de otra manera a menos que haya una razón por la que los usuarios necesiten cada fila posible, todo a la vez. Normalmente, 100,000 filas son más de lo que la persona promedio puede digerir.

+1

Es completamente posible que esto sea para exportar, o ser usado por una capa de aplicación. No conozco mucha gente que lea los resultados de las consultas SQL línea por línea. – JNK

+0

No estoy muy seguro de por qué he votado negativamente cuando dije claramente 'a menos que haya una razón por la que los usuarios necesiten todas las filas posibles de una sola vez'. –

3

Bueno, en primer lugar, hacer una subconsulta para diezmar tabla1 reducido a sólo los registros que realmente quiere ir a todos los problemas de unirse ...

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM ( 
SELECT first_name, last_name, email, CU_id FROM table1 WHERE 
table1.subscribe = 1 
AND table1.Cdate >= $startDate 
AND table1.Cdate <= $endDate 
) AS t1 
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id 
WHERE t5.store = 2 

A continuación, empezar a buscar en la modificación de la direccionalidad de las uniones .

Además, si t5.store es solo muy raramente 2, dale la vuelta a esta idea: construye la subconsulta t5, luego únela atrás y atrás y atrás.

1

Intente agregar índices en los campos a los que se une. Puede o no mejorar el rendimiento.

Además, también depende del motor que esté utilizando. Si está utilizando InnoDB, compruebe sus parámetros de configuración. Me enfrenté a un problema similar, ya que la configuración predeterminada de innodb no se escalará tanto como la configuración predeterminada de myisam.

1

Como dice todo el mundo, asegúrese de tener índices.

También puede verificar si su servidor está configurado correctamente para que pueda contener más de, o tal vez todo, el conjunto de datos en la memoria.

Sin una EXPLICACIÓN, no hay mucho por lo que trabajar.También tenga en cuenta que MySQL examinará su JOIN, e iterará a través de todas las soluciones posibles antes de ejecutar la consulta, lo que puede llevar tiempo. Una vez que tenga el orden de JOIN óptimo de EXPLAIN, podría tratar de forzar este orden en su consulta, eliminando este paso del optimizador.

2

En la actualidad, su consulta está devolviendo todas las filas coincidentes en table2-table5, solo para establecer si t5.store = 2. Si cualquiera de table2-table5 tiene un recuento de filas significativamente mayor que table1, esto puede aumentar considerablemente el número de filas procesadas - en consecuencia, la siguiente consulta puede realizar significativamente mejor:

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM table1 AS t1 
WHERE t1.subscribe =1 
AND t1.Cdate >= $startDate 
AND t1.Cdate <= $endDate 
AND EXISTS 
(SELECT NULL FROM table2 AS t2 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id AND t5.store =2 
WHERE t1.CU_id = t2.O_cid); 
Cuestiones relacionadas