我使用慢查询日志对我的数据库进行了性能分析。原来这是头号烦恼:
UPDATE
t1
SET
v1t1 =
(
SELECT
t2.v3t2
FROM
t2
WHERE
t2.v2t2 = t1.v2t1
AND t2.v1t2 <= '2012-04-24'
ORDER BY
t2.v1t2 DESC,
t2.v3t2 DESC
LIMIT 1
);
子查询本身已经很慢了。我尝试使用DISTINCT,GROUP BY和更多子查询进行变换,但是在4秒内没有执行任何操作。例如以下查询
SELECT v2t2, v3t2
FROM t2
WHERE t2.v1t2 <= '2012-04-24'
GROUP BY v2t2
ORDER BY v1t2 DESC
需要:
mysql> SELECT ...
...
69054 rows in set (5.61 sec)
mysql> EXPLAIN SELECT ...
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
| 1 | SIMPLE | t2 | ALL | v1t2 | NULL | NULL | NULL | 5203965 | Using where; Using temporary; Using filesort |
+----+-------------+-------------+------+---------------+------+---------+------+---------+----------------------------------------------+
mysql> SHOW CREATE TABLE t2;
...
PRIMARY KEY (`v3t2`),
KEY `v1t2_v3t2` (`v1t2`,`v3t2`),
KEY `v1t2` (`v1t2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
| 77070 |
+----------+
SELECT COUNT(*) FROM t2;
+----------+
| COUNT(*) |
+----------+
| 5203965 |
+----------+
我正在尝试获取最新的条目(v3t2)及其父级(v2t2)。不应该是那么大的交易,不是吗?有没有人有任何建议,我应该转向哪个旋钮?非常感谢任何帮助或提示!
这应该是一个更合适的SELECT语句:
SELECT
t1.v2t1,
(
SELECT
t2.v3t2
FROM
t2
WHERE
t2.v2t2 = t1.v2t1
AND t2.v1t2 <= '2012-04-24'
ORDER BY
t2.v1t2 DESC,
t2.v3t2 DESC
LIMIT 1
) AS latest
FROM
t1
答案 0 :(得分:1)
您的ORDER BY ... LIMIT 1
强制数据库执行表的完整扫描,只返回1行。它看起来非常像索引的候选者。
在构建索引之前,请运行以下命令检查fileds选择性:
SELECT count(*), count(v1t2), count(DISTINCT v1t2) FROM t2;
如果您的列中包含大量非NULL
值且不同值的数量超过非NULL
的40%,那么构建索引是件好事去吧。
如果index没有提供任何帮助,您应该分析列中的数据。您正在使用t2.v1t2 <= '2012-04-24'
条件,如果您的表中有一组历史记录,则不会给规划器任何内容,因为预计所有行都是过去的,因此完全扫描是无论如何最好的选择。因此,indexe是无用的。
你应该做的是思考如何以某种方式重写你的查询,只检查有限的记录子集。您的构造ORDER BY ... DESC LIMIT 1
表明您可能希望最近的条目达到'2012-04-24'
(包括)。为什么不尝试将查询重写为:
SELECT v2t2, v3t2
FROM t2
WHERE t2.v1t2 => date_add('2012-04-24' interval '-10' DAY)
GROUP BY v2t2
ORDER BY v1t2 DESC;
这只是一个例子,了解数据库的设计和数据的性质可以构建更精确的查询。
答案 1 :(得分:0)
我将看一下为子选择t2构建的索引。你应该有v2t2的索引,可能有v1t2和v3t2的索引,因为它的排序。索引应该减少子选择在更新查询中使用它们之前必须查找结果的时间。
答案 2 :(得分:0)
这有效吗?通过使用的密钥删除其中一个排序和组。
UPDATE
t1
SET
v1t1 =
(
SELECT
MAX(t2.v3t2)
FROM
t2
WHERE
t2.v2t2 = t1.v2t1
AND t2.v1t2 <= '2012-04-24'
GROUP BY t2.v1t2
ORDER BY t2.v1t2 DESC
LIMIT 1
);
UPDATE `t1`
SET `v1t1` = (
SELECT MAX(`t2`.`v3t2`)
FROM `t2`
WHERE `t2`.`v2t2` = `t1`.`v2t1`
AND `t2`.`v1t2` = (
SELECT MAX(`t2`.`v1t2`)
FROM `t2`
WHERE `t2`.`v2t2` = `t1`.`v2t1
AND `t2`.`v1t2` <= '2012-04-24'
LIMIT 1
)
LIMIT 1
);
并将此索引添加到t2
:
KEY `v2t2_v1t2` (`v2t2`, `v1t2`)