2010-12-07 3 views
7

У меня есть следующее, которое при запуске само по себе очень быстро, но когда я выполняю это для многих entity_id, запросы начинают занимать больше времени и дольше (цикл - это PHP foreach), например, этот запрос принимает только 0,078, но один и тот же запрос на другой объект в цикле занимает до 2.1 секунды, . Кажется, что запросы медленнее и медленнее, чем больше объектов, помещенных в цикле. Почему это? и как я могу улучшить/оптимизировать запрос?оптимизация скорости запросов 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 
} 

У меня есть следующие структуры таблицы:

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; 

ответ

7

Мне кажется, что у вас есть массив идентификаторов, а затем вытаскивать записи из вашей таблицы (в соответствии с вашим утверждением), где поле ID соответствует одному из значений массива.

Вместо того чтобы использовать LOOP в PHP для запуска нескольких операторов SQL, лучше всего построить один основной оператор, а затем использовать PHP для обработки результатов. Вы можете сделать это с помощью оператора 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 

Это запустит исходный запрос один раз, для всех значений идентификаторов у вас есть, сгруппированные по дате, так и значению, ид прошло. Затем вы можете использовать PHP для фильтрации результатов для определенного идентификатора из возвращаемого набора результатов.

Это намного эффективнее, чем накладные расходы, возникающие путем циклического выполнения запроса.

Ваше вернулись ResultSet будет выглядеть примерно так:

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 
2

Я не знаю, где вы получаете значение сущностей для вашего цикла, но выполнение этого запроса в цикле всегда будете большие накладные расходы. Если вы получите идентификаторы сущностей из предыдущего SQL-запроса, может возникнуть смысл реорганизовать ваш SQL, чтобы присоединиться к первому запросу с запросом цикла, чтобы вы возвращали все данные, которые вам нужны в одном SQL-запросе.

+0

Я добавил цикл PHP – Lizard 2010-12-07 09:52:31

+0

Где $ entity_ids взялся? – 2010-12-07 09:53:26

+0

Я сначала отобрал статьи из той же таблицы, которые соответствуют конкретным критериям (разные диапазоны дат), и возвратил его сущности – Lizard 2010-12-07 09:58:25

0

Грубо, с какими сущностями вы имеете дело?

Не могли бы вы вставить необходимые entites в отдельную таблицу и сделать соединение, а не иметь несколько запросов?

0

Возьмите все идентификаторы в массив, присоединиться к нему, чтобы сформировать строку и использовать «где в», чтобы получить подробную информацию в оптимизированно

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

затем сделать

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 

оптимальный путь

Смежные вопросы