如何让这个复杂的查询更快[MySQL]?

时间:2012-02-07 06:56:36

标签: mysql sql performance

我有下一个查询:

SELECT JL.j_id, COUNT(*) as total
FROM j_log JL
WHERE JL.log_time > '20120205164008'
AND JL.j_id IN (
     SELECT j_id 
     FROM j 
     WHERE checked = '1' 
     AND expires >= '20120207164008'
) GROUP BY JL.j_id ORDER BY total DESC LIMIT 3

j表中有大字结构100个字段和248986行。

下一个KEY存在于其中

  PRIMARY KEY (`j_id`),
  KEY `expires` (`expires`),
  KEY `checked` (`checked`),
  KEY `checked_2` (`checked`,`expires`)

j_log表有大约63000000条记录和下一个结构

CREATE TABLE `j_log` (
  `j_id` int(11) NOT NULL DEFAULT '0',
  `member_id` int(11) DEFAULT NULL,
  `ip` int(10) unsigned NOT NULL DEFAULT '0',
  `log_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  KEY `j_id` (`j_id`),
  KEY `log_time` (`log_time`),
  KEY `ip` (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

因此,所考虑的查询想要获得大多数访问过的j_id实例的前三名

这是计划

+----+--------------------+-------+-----------------+-----------------------------------+---------+---------+------+----------+----------+----------------------------------------------+
| id | select_type        | table | type            | possible_keys                     | key     | key_len | ref  | rows     | filtered | Extra                                        |
+----+--------------------+-------+-----------------+-----------------------------------+---------+---------+------+----------+----------+----------------------------------------------+
|  1 | PRIMARY            | JL    | index           | log_time                          | j_id    | 4       | NULL | 63914602 |     0.36 | Using where; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | j     | unique_subquery | PRIMARY,expires,checked,checked_2 | PRIMARY | 4       | func |        1 |   100.00 | Using where                                  |
+----+--------------------+-------+-----------------+-----------------------------------+---------+---------+------+----------+----------+----------------------------------------------+

有时可能需要15个!!!分钟。

有什么方法可以加快速度吗?

2 个答案:

答案 0 :(得分:0)

SELECT JL.j_id, COUNT(*) as total
FROM j_log JL
INNER JOIN j
  ON JL.j_id = j.j_id
  AND j.checked = '1'
  AND j.expires >= '20120207164008'
WHERE JL.log_time > '20120205164008'
GROUP BY JL.j_id
ORDER BY total
DESC LIMIT 3

这会更快吗?

答案 1 :(得分:0)

  • 为什么使用子查询?
  • 为什么checked是一个字符串? ('1'而不是1)
  • 为什么要差异地比较jl.log_timej.expires> vs >=

这个查询怎么样

     SELECT j.j_id, COUNT(jl.j_id) as total
       FROM j
  LEFT JOIN j_log jl ON (jl.j_id = j.j_id AND jl.checked = '1' AND jl.log_time > '20120205164008')
      WHERE j.expires >= '20120207164008'

   GROUP BY j.j_id 
   ORDER BY total DESC 
      LIMIT 3

确保j_id为两个表的PRIMARY KEY,并在j.expires和jl.checked以及jl.logtime上放置索引。 还要确保优化字段checked。我不确定可能的值是什么,但我认为它是一个布尔字段。所以请改为使用field_type BIT或使用ENUM

修改

此外,您应该将字段j.expiresjl.log_time转换为更好的字段。我认为它现在只是varchar,查看您使用的当前值:20120205164008.将其转换为DATETIME字段(但不要只是转换表,因为您将丢失数据)。