2010-12-07 13 views
7

Tengo lo siguiente que cuando se ejecuta por sí mismo es muy rápido, pero cuando estoy realizando esto para muchos entity_id las consultas comienzan a tomar más y más (el ciclo es un foreach PHP) por ejemplo esta consulta solo toma 0.078 pero la misma consulta en una entidad diferente dentro del ciclo toma hasta 2.1 segundos, las consultas parecen volverse más y más lentas cuanto más entidades pongo en el ciclo. ¿Por qué es esto? y ¿cómo puedo mejorar/optimizar la consulta?optimización de la velocidad de consulta mysql

foreach($entity_ids as $entity_id) { 
    SELECT COUNT(*) as prev, DATE_FORMAT(`created`, '%Y%m%d') AS date_group 
    FROM articles_entities 
    WHERE entity_id = '$entity_id' 
    AND `created` >= DATE_SUB(CURDATE(), INTERVAL 10 DAY) 
    GROUP BY date_group 

    // store result 
} 

que tienen la siguiente estructura de la tabla:

CREATE TABLE `articles_entities` (
    `id` CHAR(36) NOT NULL, 
    `article_id` CHAR(36) NOT NULL, 
    `entity_id` CHAR(36) NOT NULL, 
    `created` DATETIME DEFAULT NULL, 
    `modified` DATETIME DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `article_id` (`article_id`), 
    KEY `entity_id` (`entity_id`), 
    KEY `created` (`created`) 
) ENGINE=MYISAM DEFAULT CHARSET=utf8; 

Respuesta

7

Me parece que tiene un conjunto de ID, luego desea extraer registros de su tabla (de una manera controlada por su extracto) donde el campo ID coincide con uno de los valores de la matriz.

En lugar de utilizar un LOOP en PHP para ejecutar varias sentencias SQL, lo mejor que se puede hacer es crear una instrucción maestra y luego usar PHP para manejar los resultados. Esto se puede hacer mediante la instrucción SQL IN:

// where $entity_ids is an array eg 1,2,3,4,5 

    $sql="SELECT entity_id AS 'alt_entity_id', COUNT(entity_id) as prev, DATE_FORMAT(`created`, '%Y%m%d') AS 'date_group' 
    FROM articles_entities 
    WHERE entity_id IN ".implode(",",$entity_ids)." 
    AND `created` >= DATE_SUB(CURDATE(), INTERVAL 10 DAY) 
    GROUP BY date_group, entity_id"; 
    // you may wish to revese the group fields, as you require, you may also wish to change the count field to date_group, depending on what you wish to be counted 

Esto ejecutará la consulta original una vez, para todos los valores de id tenga, agrupados por tanto la fecha como el valor Identificación del pasado. A continuación, puede utilizar PHP para filtrar los resultados de la identificación específica del conjunto de resultados devuelto.

Esto es mucho más eficiente que la sobrecarga producida por el bucle de la ejecución de una consulta.

Su resultados devuelto será algo como:

entity_id | count(entity_id) | date_group 
----------|------------------|------------ 
    1  |  3   | 2010-04-01 
    1  |  3   | 2010-03-01 
    1  |  3   | 2010-02-01 
    2  |  2   | 2010-01-01 
    2  |  2   | 2010-02-01 
    3  |  1   | 2010-06-01 
    4  |  2   | 2010-06-01 
    4  |  2   | 2010-02-01 
+0

Lo único que faltaba de la respuesta era seleccionar, entity_id AS alt_entity_id, ya que podía averiguar qué entidad era cada uno (nota que no pude seleccionar solo entity_id ya que dio resultados incorrectos. También tengo que cambiar las agrupaciones. Si actualizas tu respuesta, la aceptaré. – Lizard

+0

Me alegro de que haya ayudado, he actualizado d :) – SW4

2

no sé donde está obteniendo los valores de entidad para su bucle, pero que ejecuta esta consulta dentro de un bucle siempre será una gran sobrecarga de rendimiento. Si obtiene los entity_ids de una consulta SQL previa, podría tener más sentido refactorizar su SQL para unir la consulta inicial con la consulta de bucle, de modo que esté devolviendo todos los datos que necesita en una sola consulta SQL.

+0

he añadido el php bucle – Lizard

+0

dónde viene $ entity_ids vienen? –

+0

Primero he seleccionado artículos de la misma tabla que coinciden con un criterio específico (rango de fechas diferente), y devuelto de sus entidades – Lizard

0

Aproximadamente ¿con cuántas entidades está tratando?

¿Podría insertar las entidades requeridas en una tabla separada y hacer una combinación, en lugar de tener múltiples consultas?

0

Tome todos los identificadores en una matriz, unirse a ella para formar una cadena y usar "donde en" para obtener los detalles en forma optimizada

$enitityIDS = array(); 
    foreach($entity_ids as $entity_id) { 
     $enitityIDS[]=$entity_id; 
    } 
    $entityIDString = join(",",$enitityIDS); 

luego hacer

SELECT COUNT(*) as prev, DATE_FORMAT(`created`, '%Y%m%d') AS date_group 
    FROM articles_entities 
    WHERE entity_id in (".$entityIDString.") 
    AND `created` >= DATE_SUB(CURDATE(), INTERVAL 10 DAY) 
    GROUP BY date_group, entity_id 

óptima Camino

+1

, no olvide que también necesita agrupar la consulta por el campo id, de lo contrario el resultado de la cláusula IN es indistinguible – SW4

Cuestiones relacionadas