在花了很多时间使用这个问题的变体后,我想知道是否有人可以帮我优化这个查询或索引。
我有三个临时表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”)
是否有一些明显我遗漏的东西会妨碍临时表的使用?
答案 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在查询执行期间创建临时表。如果您希望创建一个子查询(或表),以最大限度地减少连接所需的操作数量,这可能会加快查询速度,但我没有看到正在选择联接数据。