mysql查询速度优化

时间:2010-12-07 09:47:33

标签: php mysql optimization

我有以下内容,当它自己运行时非常快,但是当我为许多entity_id执行此操作时,查询开始花费的时间越来越长(循环是PHP foreach),例如此查询只需要0.078但是循环内不同实体上的相同查询需要2.1秒,查询似乎越慢越慢,我放入循环中的实体越多。为什么是这样?以及如何改进/优化查询?

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;

4 个答案:

答案 0 :(得分:7)

在我看来,你有一个ID数组,然后想要从你的表中提取记录(以你的语句控制的方式),其中ID字段匹配其中一个数组值。

不是在PHP中使用LOOP来运行多个SQL语句,最好的做法是构建一个master语句,然后使用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

这将针对您拥有的所有id值运行原始查询一次,按日期和传递的id值进行分组。然后,您可以使用PHP从返回的结果集中过滤掉特定id的结果。

这比循环执行查询所产生的开销更有效。

您返回的结果集将类似于:

 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

答案 1 :(得分:2)

我不知道你在哪里获得循环的实体值,但在循环中执行此查询将始终是一个很大的性能开销。如果您从先前的SQL查询中获取entity_ids,则重构SQL以使用循环查询加入初始查询可能更有意义,这样您就可以在单个SQL查询中返回所需的所有数据。

答案 2 :(得分:0)

你大概有多少实体在处理?

您是否可以将所需的entites插入单独的表并进行连接,而不是多次查询?

答案 3 :(得分:0)

将所有ID放入数组中,将其连接以形成字符串并使用“where in”以优化方式获取详细信息

$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

最佳方式