优化查询以避免使用临时表

时间:2014-07-01 08:53:35

标签: mysql sql optimization

我因为一个我无法优化的简单查询而陷入困境2天...... 我的表包含大约60,000,000行:

CREATE TABLE IF NOT EXISTS `pages_objects_likes` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `page_id` bigint(20) unsigned NOT NULL,
  `object_id` bigint(20) unsigned NOT NULL,
  `user_id` bigint(20) unsigned NOT NULL,
  `created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `pages_objects_likes_page_id_created_time_index` (`page_id`,`created_time`)
) ENGINE=InnoDB ;

我的查询是:

SELECT c.user_id, c.page_id,
COUNT(*) AS total
FROM pages_objects_likes c
WHERE page_id IN (116001391818501,37823307325,45502366281,30166294332,7133374462,223343965320,9654313055,123096413226,231809706871226,246637838754023,120063638018636)
AND created_time >= DATE_SUB('2014-06-30', INTERVAL 1 YEAR)
AND created_time < DATE_SUB('2014-06-30', INTERVAL 6 MONTH)
GROUP BY c.user_id, c.page_id

但当我EXPLAIN时,我明白了:

Using index condition; Using temporary; Using filesort

我想优化索引或查询,因为它需要花费很长时间才能执行(超过5分钟)。 我的服务器有SSD,32Gb或RAM以及专用于MySQL的4 Core i5,因此它不是硬件问题:)

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

好的,我找到了解决方案!

像这样更新索引:

KEY `pages_objects_likes_page_id_created_time_index` (`page_id`,`user_id`,`created_time`)

通过反转group by语句来更新查询:

GROUP BY c.page_id, c.user_id

索引现在随处可用;)

答案 1 :(得分:-1)

我猜你的问题是DATE_SUB函数,一般来说使用WHERE中的函数是个坏主意,因为

  1. 他们评估表格中的每一条记录。
  2. 数据库引擎通常在将字段传递给函数时跳过索引。
  3. 我的建议是从客户端传递DATE_SUB输出,或者在查询开始之前计算一次。

    我也可能想在“created_time”,“page_id”,“user_id”上放一个索引,看看它是怎么回事。