2010-07-18 8 views
5

Tengo un sitio web donde los visitantes pueden dejar comentarios. Deseo agregar la capacidad de responder comentarios (es decir, comentarios anidados).Optimizar IZQUIERDA unir en la tabla con más de 30 000 filas

Al principio esta consulta era rápido, pero después de que poblaban la mesa con los comentarios existentes (aproximadamente 30000) una consulta simple como:

SELECT c.id, c2.id 
    FROM (SELECT id 
     FROM swb_comments 
     WHERE pageId = 1411 
     ORDER BY id DESC 
     LIMIT 10) AS c 
    LEFT JOIN swb_comments AS c2 ON c.id = c2.parentId 

tomó más de 2 segundos, sin childComments (!).

¿Cómo puedo optimizar una consulta como esta? La posible solución sería http://www.ferdychristant.com/blog//articles/DOMM-7QJPM7 (desplácese hasta "El modelo de tabla plana hecho a la derecha") pero esto dificulta la paginación (¿cómo limito a 10 comentarios principales en 1 consulta?)

La tabla tiene 3 índices, id, pageId y ParentId.

¡Gracias de antemano!

EDITAR:

Definición de tabla agregada. Esta es la definición completa con algunas diferencias a la consulta SELECT anterior, (es decir pageID en lugar de numberId para evitar confussion)

CREATE TABLE `swb_comments` (
    `id` mediumint(9) NOT NULL auto_increment, 
    `userId` mediumint(9) unsigned NOT NULL default '0', 
    `numberId` mediumint(9) unsigned default NULL, 
    `orgId` mediumint(9) unsigned default NULL, 
    `author` varchar(100) default NULL, 
    `email` varchar(255) NOT NULL, 
    `message` text NOT NULL, 
    `IP` varchar(40) NOT NULL, 
    `timestamp` varchar(25) NOT NULL, 
    `editedTimestamp` varchar(25) default NULL COMMENT 'last edited timestamp', 
    `status` varchar(20) NOT NULL default 'publish', 
    `parentId` mediumint(9) unsigned NOT NULL default '0', 
    `locale` varchar(10) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `userId` (`userId`), 
    KEY `numberId` (`numberId`), 
    KEY `orgId` (`orgId`), 
    KEY `parentId` (`parentId`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=34748 ; 
+0

¿Está planeando hacer anidación ilimitada? (es decir, ¿puedes responder de nuevo a una respuesta?) ¿O solo un nivel de profundidad máxima? –

+2

¿Qué dice EXPLAIN? –

+0

¿Es SELECCIONAR ID FROM swb_comments DONDE pageId = 1411 LIMIT 10 lento también? ¿Cuántas visitas recibe de la unión de identificación de padres? –

Respuesta

1

La cuestión es que MySQL no puede aplicarse índice si lo necesitan para hacer frente a un resultado de un derivado consulta (es por eso que tiene NULL en la columna de las posibles claves). Así que sugiero para filtrar los diez comentarios que usted necesita:

SELECT * FROM swb_comments WHERE pageId = 1411 ORDER BY id DESC LIMIT 10 

Y después de eso Enviar solicitud separada para obtener respuestas para cada comentario id:

SELECT * FROM swb_comments WHERE parentId IN ($commentId1, $commentId2, ..., $commentId10) 

En este motor de base de caso será capaz de aplicar los índices pageId y parentId de manera eficiente.

+0

¡Gracias! Voy a probar esto! –

+0

Normalmente, declinaba esto, pero habiéndome topado con innumerables cosas extrañas con el optimizador MySQL que la mayoría de los otros proveedores no tienen, solo tengo que asentir con la cabeza en total acuerdo. – Joe

0

Si el señor Fedorenko es correcta y la subconsulta está causando las dificultades optimizador, no se podía tratar ...

SELECT c.id, c2.id 
    FROM swb_comments c LEFT JOIN swb_comments c2 ON c.id = c2.parentID 
    WHERE c.pageId = 1411 
    ORDER BY c.id DESC 
    LIMIT 10; 

y ver si te sirve de mejora?

Más tarde: he creado una tabla con su definición, la rellené con 30,000 filas esquemáticas e intenté ambas consultas. Ambos se completan en un tiempo demasiado corto para darse cuenta. Los planes de explicación están aquí ...

mysql> EXPLAIN SELECT c.id, c2.id 
       FROM swb_comments c LEFT JOIN swb_comments c2 ON c.id = c2.parentID 
       WHERE c.numberId = 1411  ORDER BY c.id DESC  LIMIT 10; 
+----+-------------+-------+------+---------------+----------+---------+------------+------+-----------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra      | 
+----+-------------+-------+------+---------------+----------+---------+------------+------+-----------------------------+ 
| 1 | SIMPLE  | c  | ref | numberId  | numberId | 4  | const  | 1 | Using where; Using filesort | 
| 1 | SIMPLE  | c2 | ref | parentId  | parentId | 3  | books.c.id | 14 |        | 
+----+-------------+-------+------+---------------+----------+---------+------------+------+-----------------------------+ 

mysql> EXPLAIN SELECT c.id, c2.id 
        FROM swb_comments c LEFT JOIN swb_comments c2 ON c.id = c2.parentID 
        WHERE c.numberId = 1411  ORDER BY c.id DESC  LIMIT 10; 
+----+-------------+-------+------+---------------+----------+---------+------------+------+-----------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra      | 
+----+-------------+-------+------+---------------+----------+---------+------------+------+-----------------------------+ 
| 1 | SIMPLE  | c  | ref | numberId  | numberId | 4  | const  | 1 | Using where; Using filesort | 
| 1 | SIMPLE  | c2 | ref | parentId  | parentId | 3  | books.c.id | 14 |        | 
+----+-------------+-------+------+---------------+----------+---------+------------+------+-----------------------------+ 

y son exactamente lo que esperaría.

Esto es muy misterioso.

Lo pensaré un poco más para ver si hay algo más que podamos probar.

+0

Esta fue mi consulta original, pero no admite la paginación de los comentarios de los padres. Y esta consulta es de hecho mucho más lenta, aproximadamente 32 segundos. –

+0

Hmm. Eso me sorprende ¿Qué dice el EXPLAIN al respecto? –

+0

He actualizado http://carl-fredrik.net/explain.html con una EXPLICACIÓN para la consulta anterior. Creo que el "uso de dónde; Uso temporal; Uso de filesort" soy el culpable aquí. –

Cuestiones relacionadas