2010-08-16 16 views
5

Tengo la siguiente situación: en una base de datos MySQL, tengo 2 tablas MyISAM, una con 4,2 millones de filas y otra con 320 millones de filas. El siguiente es el esquema de las tablas:MySQL consulta lenta con join aunque EXPLAIN muestra buen plan

Tabla 1 (4,2 millones de filas)

F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY 
f2 varchar(40) 
f3 varchar(40) 
f4 varchar(40) 
f5 varchar(40) 
f6 smallint(6) 
f7 smallint(6) 
f8 varchar(40) 
f9 varchar(40) 
f10 smallint(6) 
f11 varchar(10) 
f12 tinyint(4) 
f13 smallint(6) 
f14 text 

Tabla 2 (320M filas)

F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY 
f2 INTEGER UNSIGNED NOT NULL 

Tabla 2 se encuentra en una base de datos diferente, pero estoy usando un almacenados procedimiento que consulta las dos tablas. La relación entre las dos tablas es que para Table1.F1 puede haber hasta aprox. 100 filas en Table2.F1 (clave externa) que coinciden, y se devolverá el valor para Table2.f2 para estas claves coincidentes. I tienen un IX1 índice (f2 (15), f3 (10)) En la Tabla 1 y un IX2 índice (F1, F2) y IX3 (f2) en la Tabla 2

Las consultas Estoy funcionando son los siguientes:

SELECT g.F1 
FROM DB1.Table1 g 
INNER JOIN DB2.Table2 gp ON g.F1 = gp.F1 
WHERE (gp.f2 = 452677825) AND 
(g.f2 = 'A string value') LIMIT 0,56 

Esta consulta es a veces muy rápido (< 1s) pero cambiando el valor de cadena que g.F2 se compara con cables a las preguntas que tienen incluso más de 11 ya veces hasta 30 segundos. No puedo entender por qué esto es así. A continuación se muestra el resultado de EXPLAIN en SELECT que se ejecuta.

1, 'SIMPLE', 'g', 'ref', 'PRIMARY,IX1', 'IX1', '17', 'const', 901, 'Using where' 
1, 'SIMPLE', 'gp', 'ref', 'IX3,IX2', 'IX2', '8', 'DB1.g.F1,const', 1, 'Using index' 

que parece ser un plan de ejecución bastante bueno. El número de filas en la fila superior de la explicación va a 2000 como máximo, pero no veo por qué esto debería tomar más de una fracción de segundo para devolver los resultados. También ejecuté un perfil en la consulta y noté que las consultas están pasando el 99.9% del tiempo en la etapa "Envío de datos". ¿Puede alguien explicar por qué esto es así y qué se puede hacer para optimizar la consulta?

Gracias de antemano, Tim

+0

¿Las consultas que funcionan más lentamente también tienden a ser aquellas que devuelven más datos? –

+0

Hola Will. Gracias por tu comentario. Las consultas regresarán en la mayoría de las 56 filas, ya que estoy LIMITANDO la declaración. Sin embargo, como regla general, cuantas más filas haya en la fila superior de EXPLAIN, más tiempo lleva, pero no siempre es así. – Tim

+0

¿El hecho de aumentar el tamaño de la cantidad de caracteres incluidos desde f2 en IX1 en la Tabla 1 tiene algún efecto en el rendimiento? Específicamente, ¿aumentar esto a 40 mejora las cosas en absoluto? –

Respuesta

1

no soy un experto en esta área, pero aquí están algunas ideas:

velocidad de las consultas tomando más tiempo cuando g.F2 cambios es a causa de almacenamiento en caché. MySQL guardará los resultados para cada consulta (hasta que la memoria caché esté llena), pero las nuevas consultas se ejecutarán en una memoria caché vacía, por lo que tardarán más. No deberías optimizar basado en esto. (Ver How to measure accurately)

no puedo decir de su información si la tabla g o gp tiene una mayor especificidad (parece que gp?) En la cláusula where, pero es posible que desee probar una subconsulta en su lugar. (Ver How to force the inner query to execute first)

En cuanto a los perfiles, es posible que usted está golpeando un umbral físico, como superior a la asignación de memoria RAM (mediante intercambio es desastroso para el rendimiento) que no sería obvio a partir explain, o si explain está mal en este caso.

+0

Hola, Gracias por su comentario. En este momento he cambiado la consulta anterior para usar IN en lugar de una combinación, como sugirió. La consulta ahora tiene el siguiente aspecto: SELECCIONE g.F1 FROM (SELECCIONE g.F1 FROM DB1.Table1 g WHERE (g.f2 = 'abc')) COMO DONDE A.F1 IN (SELECCIONE gp.F1 FROM DB2. Table2 gp DONDE (gp.f2 = 452677825)) LÍMITE 0,56 y la consulta se ejecuta mucho más rápido (~ 1s, 2s max). ¡Mi misión es tratar de reducir esto aún más si es posible! – Tim

0

Si puede intentar retocar su my.cnf, la propiedad con la que desea jugar es key_buffer_size. Los índices MyISAM se almacenan en archivos .MYI si los ubica y totaliza los tamaños de archivo (por ejemplo, ls -lh /var/lib/mysql/dbname/*.MYI), puede estimar aproximadamente qué tan grande debe ser el almacenamiento intermedio de claves para adaptarse todos sus índices en. Sin embargo, los documentos de MySQL recomiendan no exceder el 25% de la memoria del sistema.

0

La relación entre las dos tablas es que para Table1.F1 puede haber hasta aprox. 100 filas en Table2.F1

para aclarar, es la relación entre Table1.F1Table2.F1 y uno-a-uno, o uno a muchos? Para mí, esta afirmación implica de uno a muchos, pero desde el esquema, cada uno de los campos son claves primarias (es decir, únicas).

En cualquier caso, sospecho que el uniforme de g.f2(15) no es uniforme, y que cuando se atacan los valores atípicos estadísticos, el rendimiento se degrada en consecuencia.

¿Los resultados de

SELECT f2(15) AS f2_15, COUNT(*) AS cnt 
FROM Table1 
GROUP BY f2(15) 
ORDER BY cnt DESC 

muestran algunos valores extremos significativos?

Cuestiones relacionadas