2010-04-17 12 views
5

Tengo un enunciado sql en el que me uno a 4 tablas, cada una con 200,000 filas. La consulta se ejecuta, pero se mantiene congelada. Cuando hago una combinación en 3 tablas en su lugar, devuelve las filas (toma aproximadamente 10 segundos). Alguna sugerencia por qué? sugerencias para acelerar?¿Los resultados de la consulta tardan demasiado en la base de datos 200K, aceleran las sugerencias?

Gracias!

Código

SELECT * 
FROM equipment, tiremap, workreference, tirework 
WHERE equipment.tiremap = tiremap.`TireID` AND 
     tiremap.`WorkMap` = workreference.`aMap` AND 
     workreference.`bMap` = tirework.workmap 
LIMIT 5 

ps

y si ayuda alguna, estoy usando la alquimia SQL para generar este código, el código sqlalchemy de esto es

query = session.query(equipment, tiremap, workreference, tirework) 
query = query.filter(equipment.c.tiremap == tiremap.c.TireID) 
query = query.filter(tiremap.c.WorkMap==workreference.c.aMap) 
query = query.filter(workreference.c.bMap == tirework.c.workmap) 
query = query.limit(5) 
query.all() 
+0

¿Siempre es la misma tabla que excluye para que funcione? En otras palabras, ¿puede hacer que funcione con 3 de las 4 tablas posibles? ¿O es 1 tabla particular que siempre es el problema? – MusiGenesis

+0

¿Ha ejecutado esto a través de EXPLAIN para ver qué está haciendo? Ese debería haber sido tu primer paso. – ryeguy

+0

@MusiGenesis, pude ejecutar el sql a una velocidad decente durante las primeras 3 tablas, pero una vez que comencé a unirme con el trabajo de neumáticos, parece congelarse y nunca responder, ¿cuál crees que es el problema? – colorfulgrayscale

Respuesta

5

Asegúrese de tener índices en:

  • equipo (tiremap)
  • tiremap (TireID)
  • tiremap (WorkMap)
  • workreference (AMAP)
  • workreference (BMAP)
  • trabajo de neumáticos (workmap)

Editar: Supongo que debería proporcionar un contexto para que esté completo.

El optimizador de SQL examina una declaración, la analiza y luego determina un plan de ejecución para ella en función de la consulta, las tablas a las que se hace referencia y los índices disponibles. Si haces SELECT * FROM tab1 entonces hará un escaneo de tabla completo de tab1 porque no hay otra manera de ejecutar eso.

Si tiene SELECT * FROM person WHERE lastname LIKE 'V%' y tiene un millón de registros, será lento interrogar cada fila, pero si lastname está indexado, es mucho más eficiente.

Con una consulta como la suya, una de esas tablas será la guía que, independientemente de los índices, se puede realizar simplemente como una exploración de tabla completa. No hay nada de malo en esto Una tabla tiene que conducir la consulta. Si hay una cláusula WHERE (para algo distinto de las condiciones de unión), esto puede cambiar, pero de lo contrario es generalmente verdadero.

Desde esa mesa de conducción, MySQL comenzará a agregar uniones al plan de ejecución. Estas uniones requerirán índices del otro lado para hacer que esto funcione de manera eficiente.

Por lo tanto, con tres tablas, puede tener una tabla que no esté indexada, pero no importa, ya que dirige la consulta. Con la cuarta tabla, puede haber dos tablas sin indexar y eso ahora es un problema porque para cada fila en una MySQL tendrá que hacer una exploración completa de la tabla de la otra.

Básicamente, usted crea un índice en cada clave externa y se une a la columna para que MySQL pueda usar lo que está disponible para hacer el mejor plan de ejecución para la consulta que le da.

Por último, la mayoría de las herramientas le informarán sobre el esquema de la base de datos. PHPMyAdmin es popular para bases de datos alojadas. Personalmente, me gusta una aplicación de escritorio para este tipo de cosas. Navicat Lite es una herramienta gratuita decente para esto.

+0

hombre impresionante, lo comprobaré. 'preesh. – colorfulgrayscale

+0

también, ¿hay alguna manera de saber si las tablas están indexadas o no? ok, nvm, simplemente lo busqué en Google. Gracias. – colorfulgrayscale

+0

@colorfulgrayscale agregó algo de contexto a mi afirmación. – cletus

0

Podría ser que la 4ta mesa a la que te estás uniendo es mucho más grande que las otras. También podría ser que la columna a la que se une no tenga un índice.

0

La mayoría de las bases de datos SQL tienen alguna variación de "EXPLICAR PLAN" o "EXPLICAR" que puede utilizar para ver cómo se analiza la consulta. Busque escaneos completos de tablas como un lugar donde necesita índices.

1

Usted está haciendo una combinación natural de 4 tablas. Además, en su declaración "DONDE", no hay condiciones especiales.

El motor de base de datos va a hacer lo siguiente:

lo hará primero un producto recursiva de todos los datos de cada tabla.

Considere las siguientes filas en las tablas A, B y C:

A = rowA1 
    rowA2 
    rowA3; 
B = rowB1 
    rowB2 
    rowB3; 
C = rowC1 
    rowC2 
    rowC3; 

Básicamente, si lo hace unirse a un natural de las 3 mesas, el motor tendrá en la memoria:

rowA1 - rowB1 - rowC1 
rowA1 - rowB1 - rowC2 
rowA1 - rowB1 - rowC3 
rowA1 - rowB2 - rowC1 
rowA1 - rowB2 - rowC2 
rowA1 - rowB2 - rowC3 
rowA1 - rowB3 - rowC1 
rowA1 - rowB3 - rowC2 
rowA1 - rowB3 - rowC3 
... 
... 
... 
rowA3 - rowB3 - rowC1 
rowA3 - rowB3 - rowC2 
rowA3 - rowB3 - rowC3 

En total, 27 filas se ponen en la memoria. Sin embargo, sólo queremos 3 filas:

rowA1 - rowB1 - rowC1 
rowA2 - rowB2 - rowC2 
rowA3 - rowB3 - rowC3 

Si el motor de base de datos no hace optimización por sí mismo, se unen a un natural de la tabla 3 es muy caro. Para 4 tablas, es inconcebible, incluso para un número limitado de filas.

Ahora, ¿cómo podemos obtener algo mejor?

Primero, al mirar el código, sabemos que solo necesitamos 5 valores. Además, en la optimización de la base de datos, se dice que debe hacer SELECCIONAR lo más temprano posible.

Aquí hay algunos códigos no probados que deberían ser de ayuda. Puede que tenga que modificarlo, dependiendo de qué motor de base de datos que está utilizando:

SELECT * 
FROM (SELECT * FROM equipment LIMIT 5) e, tiremap, workreference, tirework 
WHERE e.tiremap = tiremap.TireID AND 
     tiremap.WorkMap = workreference.`aMap` AND 
     workreference.`bMap` = tirework.workmap 

Sólo al hacer esto, se debe sentir como que tenía sólo 3 mesas, y no 4. Sin embargo, esto no es realmente lo que querer. Si una fila de "equipo" no está referenciada en las otras tablas, obtendrá menos de 5 filas al final. Sin embargo, este es un ejemplo para mostrarle que tal vez no necesitemos todas las filas de todas las tablas.

Ahora, lo que creo que quieren que podría ser la siguiente:

SELECT * FROM equipment 
INNER JOIN tiremap ON equipment.tiremap = tiremap.TireID 
INNER JOIN workreference ON tiremap.WorkMap = workreference.aMap 
INNER JOIN tirework ON workreference.bMap = tirework.workmap 
LIMIT 5 

Es posible que haya un problema aquí: si el motor no es tan bueno (MySQL, lo siento), puede tomar mucho tiempo.

Si realmente quiere hacer la optimización de sí mismo:

SELECT * FROM tirework, 
    (SELECT * FROM workreference, 
     (SELECT * FROM tiremap, 
      (SELECT * FROM equipment) e 
     WHERE e.tiremap = tiremap.TireID) t 
    WHERE t.WorkMap = workreference.aMap) w 
WHERE w.bMap = tirework.workmap 
LIMIT 5 

y listo! Incluso si su optimizador del motor no existe, esa consulta no debería tomar demasiado tiempo. En lugar de hacer un gran producto de todo, su motor hará un producto a la vez y obtendrá las malas filas antes de unirse a ella con una nueva tabla.

Pruébalo.

+0

zomg, muchas gracias. Esto es exactamente lo que estaba buscando. paz. – colorfulgrayscale

Cuestiones relacionadas