使用GROUP BY和JOIN进行MySQL性能

时间:2011-06-30 21:11:31

标签: mysql performance

在花了很多时间使用这个问题的变体后,我想知道是否有人可以帮我优化这个查询或索引。

我有三个临时表ref1,ref2,ref3全部定义如下,ref1和ref2各有大约6000行,ref3只有3行:

CREATE TEMPORARY TABLE ref1 (
  id INT NOT NULL AUTO_INCREMENT,
  val INT,
  PRIMARY KEY (id)
)
ENGINE = MEMORY;

慢速查询是针对这样的表,大约有1M行:

CREATE TABLE t1 (
  d DATETIME NOT NULL,
  id1 INT NOT NULL,
  id2 INT NOT NULL,
  id3 INT NOT NULL,
  x INT NULL,
  PRIMARY KEY (id1, d, id2, id3)
)
ENGINE = INNODB;

有问题的查询:

SELECT id1, SUM(x)
  FROM t1
  INNER JOIN ref1 ON ref1.id = t1.id1
  INNER JOIN ref2 ON ref2.id = t1.id2
  INNER JOIN ref3 ON ref3.id = t1.id3
  WHERE d BETWEEN '2011-03-01' AND '2011-04-01'
  GROUP BY id1;

临时表用于将结果集过滤到用户正在查找的项目。

EXPLAIN

+----+-------------+-------+--------+---------------+---------+---------+------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref              | rows | Extra                           |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+---------------------------------+
|  1 | SIMPLE      | ref1  | ALL    | PRIMARY       | NULL    | NULL    | NULL             | 6000 | Using temporary; Using filesort |
|  1 | SIMPLE      | t1    | ref    | PRIMARY       | PRIMARY | 4       | med31new.ref1.id |   38 | Using where                     |
|  1 | SIMPLE      | ref3  | ALL    | PRIMARY       | NULL    | NULL    | NULL             |    3 | Using where; Using join buffer  |
|  1 | SIMPLE      | ref2  | eq_ref | PRIMARY       | PRIMARY | 4       | med31new.t1.id2  |    1 |                                 |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+---------------------------------+

(在~5M行的另一个系统上,EXPLAIN在列表中首先显示t1,“使用where;使用索引;使用临时;使用filesort”)

是否有一些明显我遗漏的东西会妨碍临时表的使用?

3 个答案:

答案 0 :(得分:2)

第一个filesort并不意味着文件在磁盘上是可写的以执行排序,它是mySQL中quicksort算法的名称,请检查what-does-using-filesort-mean-in-mysql

因此,解释中有问题的关键字是Using temporary,而不是Using filesort。为此你可以玩tmp_table_size& max_heap_table_size(在两者上放置相同的值)以允许更多的内存工作并避免临时表创建,请检查this link on the subject with remarks about documentation mistakes

然后你可以尝试不同的索引策略,并查看结果,但不要试图避免使用filesort。

最后一点,不相关,你创建一个SUM(x)但x可以取NULL值,如果你不希望Group上的任何NULL值使你的和为NULL,那么SUM(COALESCE(x) , 0)可能更好。

答案 1 :(得分:0)

在JUST DATE添加一个索引。由于这是第一个表的标准,而其他表只是连接,因此它将首先针对DATE进行优化...连接是次要的。

答案 2 :(得分:0)

不是这个:

SELECT id1, SUM(x)
  FROM t1
  INNER JOIN ref1 ON ref1.id = t1.id1
  INNER JOIN ref2 ON ref2.id = t1.id2
  INNER JOIN ref3 ON ref3.id = t1.id3
  WHERE d BETWEEN '2011-03-01' AND '2011-04-01'
  GROUP BY id1;

完全等同于:

select id1, SUM(x)
  FROM t1
  WHERE d BETWEEN '2011-03-01' AND '2011-04-01'
  group by id1;

使用的额外表格是什么?我认为另一个答案中提到的临时表是指MySQL在查询执行期间创建临时表。如果您希望创建一个子查询(或表),以最大限度地减少连接所需的操作数量,这可能会加快查询速度,但我没有看到正在选择联接数据。