2010-06-28 32 views
5

La siguiente consulta funciona, pero es muy lenta para 10 registros (2 segundos). El perfilado dice que está creando una tabla tmp, pero no estoy seguro de por qué.MySQL - ¿Cómo se puede optimizar esta consulta?

Básicamente, me estoy uniendo al usuario actual, a los grupos acl, para obtener todos los grupos en los que están, unir los grupos a las empresas, obtener todas las empresas en las que están, unirme a las empresas a las órdenes , para obtener todos los órdenes ..

Si quito esta línea

ORDER BY orders.created_on DESC 

continuación, la consulta se ejecuta en 0,06 segundos (más que aceptable) ..

Ayuda, alguna idea sobre cómo optimizar ? Muchas gracias :)

SELECT 
    orders.uuid, 
    companies.name as company_name 
FROM 
    users u 
JOIN  
    users_acl_groups g on u.uuid = g.user_uuid 
JOIN 
    users_acl acl on (acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid) 
JOIN 
    companies on acl.item_uuid = companies.uuid 
JOIN 
    orders on companies.uuid = orders.company_uuid 
WHERE 
    u.uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and orders.status <> '' 
ORDER BY orders.created_on DESC 

limit 0, 10; 

UPDATE, el explicar de la consulta ..

órdenes

1 SIMPLE ALL 9403 Usando temporal; Usando filesort

1 SIMPLE acl ALL 1859 Usando where; Uso de la memoria tampón de unión

1 SIMPLE g ALL 2005 Using where; El uso de unirse a búfer

1 empresas SIMPLE eq_ref PRIMARIA PRIMARIA 52 table.orders.company_uuid 1

1 SIMPLE u all 33595 Uso de dónde; Distinto; Uso de unirse a tampón

+0

Modificó su título, adivinando que le costó un voto negativo debido a su tono imperativo y exigente cuando su pregunta está bien redactada. –

+0

Intenta usar la misma consulta con join aplicada en cualquier columna que no sea UID. Intente hacerlo con int, float, string, UID y observe la hora. Permítanos también saber si encuentra alguna variación. –

+0

¿Tiene un índice en orders.created_on? Muestra el resultado en 'EXPLAIN' en tu consulta. Tal vez podrías beneficiarte de otros índices. Que 'EXPLAIN' nos dirá. – nos

Respuesta

2

¿Usted ha considerado hacer una tabla diseño de estilo hecho, como un paso desnormalización?

Básicamente se trata de una especie de muchos-a-muchos tabla de intersección, por ejemplo:

CREATE TABLE user_order_fact (
    user_uuid ... 
    order_uuid ... 
    order_created_on ... 
    order_status ... 
    company_name ..., 
    primary key (user_uuid, order_uuid), 
    key (user_uuid, order_status, order_created_on, order_uuid, company_name) 
); 

... fill with data ... 

SELECT 
    order_uuid, 
    company_name 
FROM 
    user_order_fact 
WHERE 
    user_uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and order_status <> '' 
ORDER BY order_created_on DESC 

limit 0, 10; 

supongo en el índice compuesto. Tendrás que experimentar hasta que lo hagas bien. Básicamente, está intentando que el plan del optimizador informe que es con el índice.

Por supuesto, esto es almacenar datos de forma redundante y en forma desnormalizada, por lo que debe configurar algunos desencadenadores para mantener esto sincronizado con las tablas normalizadas.

+0

Hmm tal vez el PK sea solo order_uuid. No estoy garantizando que este sea el mejor diseño, solo intento darte una idea de lo que quiero decir. –

0

asegúrese de que "orders.created_on" tiene un índice ... Si lo hace, entonces el enfoque de Bill en la parte superior será el mejor, sin embargo, requerirá un poco de trabajo.

+0

Creo que sí? KEY 'created_on' (' created_on') – Brett

0

Es difícil de responder sin saber mucho sobre los índices existentes o el volumen de cada tabla.

Además, sin mucha información sobre el modelo ... ¿la búsqueda devuelve todos los resultados?

¿Todos los usuarios pertenecen a un grupo? Parece que no ... y la consulta no devolverá usuarios fuera de un grupo.

¿Puede un grupo pertenecer a un grupo y solicitar una consulta recursiva?

+0

Estaba tratando de resolver esa consulta recursiva, pero no estaba teniendo mucha suerte :(la tabla es silenciosa, 10.000 registros. No hay índices en este momento ... – Brett

+0

@Brett: Los índices, si están presentes en este caso, no funcionarán, ya que el operador NOT y el operador Like no usan los índices –

0

No estoy seguro de cuál podría ser el motivo exacto por el que tarda 2 seg. Lo cual no es posible ir a buscar para esta consulta 10 registros, pero es lo que vemos aquí son

  1. acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid

    UID basan unirse, puede ser que usted es también usarlo como clave principal como respondidas anteriormente.

  2. ORDER BY orders.created_on. Usar Order by en date no sería tan óptimo como usar PK o cualquier valor entero es más apropiado.

  3. orders.status <> '' Si se utiliza todos los índices de las tablas a continuación, ningún índice se puede utilizar en esta consulta porque NO operador y de igual operador no significa utiliza índices cuando se utiliza en cualquier consulta.

  4. El volumen de registros presentes en una tabla puede ser otro motivo, pero solo por los factores anteriores. De lo contrario, podría haber manejado un gran volumen también.

factor importante que contribuye que creo que es UID se utiliza en une manera que todas las tres condiciones que eviten se pueden ver en su consulta que podría hacer su consulta perezosos

+0

Hola, gracias por tus respuestas ... ¿Qué significa minimizar en no.2? – Brett

0

algunas ideas:

En realidad, no selecciona orders.created_on en Su consulta. Por lo tanto, no tiene sentido ordenar en esa columna. Tal vez, seleccionarlo (SELECT orders.created_on ...) ayudaría al rendimiento (Solo supongo que no tengo idea de lo que estoy hablando aquí).

Siempre puede ordenar en su aplicación, si no hay una enorme cantidad de registros devueltos por su consulta.

A veces es más adecuado para el rendimiento utilizar N pequeñas consultas en lugar de 1 gran consulta sql. Pseudocódigo:

user_id = get_one("SELECT uuid FROM users WHERE ..."); 
group_ids = get_many("SELECT uuid FROM groups WHERE user_uuid = " + user_id); 
comps_ids = get_many("SELECT DISTINCT item_uuid FROM acls WHERE user_uuid = " + user_id + " OR group_uuid IN " + groups_ids.to_q()); 
orders = get_many("SELECT * FROM orders WHERE company_uuid IN " + comps_ids.as_q() + " WHERE status <> '' ORDER BY created_on"); 
Cuestiones relacionadas