一个给所有MySQL专家的:-)
我有以下疑问:
SELECT o.*, p.name, p.amount, p.quantity
FROM orders o, products p
WHERE o.id = p.order_id AND o.total != '0.00' AND DATE(o.timestamp) BETWEEN '2012-01-01' AND '2012-01-31'
ORDER BY o.timestamp ASC
订单表=80900行
产品表=125389行
o.id和p.order\u id被索引
查询大约需要6秒才能完成-这太长了。我正在寻找一种方法来优化它,可能使用临时表或其他类型的连接。恐怕我对这两个概念的理解都很有限。
有人能给我推荐一个优化这个查询的方法吗?
最佳答案
首先,我会使用不同的语法风格。ANSI-92
已经有20年的时间了,许多RDBMS实际上建议不要使用您使用过的符号。在这种情况下不会有什么不同,但这确实是一个很好的做法,原因有很多(我会让你自己调查并做出决定)。
最终答案和示例语法:
SELECT
o.*, p.name, p.amount, p.quantity
FROM
orders
INNER JOIN
products
ON orders.id = products.order_id
WHERE
orders.timestamp >= '2012-01-01'
AND orders.timestamp < '2012-02-01'
AND orders.total != '0.00'
ORDER BY
orders.timestamp ASC
因为
orders
表是您进行初始筛选的表,所以这是一个非常好的开始考虑优化的地方。使用
DATE(o.timestamp) BETWEEN x AND y
可以在一月成功获取所有日期和时间。但这需要对DATE()
表中的每一行调用orders
函数(类似于RBAR的意思)。RDBMS无法看透这个函数,只知道如何避免浪费时间。相反,我们需要进行优化,重新安排数学,使其不需要我们正在过滤的字段上的函数。 orders.timestamp >= '2012-01-01'
AND orders.timestamp < '2012-02-01'
这个版本允许乐观主义者知道你想要一个日期块,所有的日期都是连续的。这叫做范围搜索。它可以使用索引快速找到符合该范围的第一条记录和最后一条记录,然后选择其中的每条记录。这样可以避免检查所有不适合的记录,甚至避免检查范围中间的所有记录;只需要找出边界。
假设所有的记录都是按日期排序的,乐观者可以看到这一点。为此,您需要一个索引。考虑到这一点,似乎可以使用两个基本的覆盖索引:
-
(id, timestamp)
-
(timestamp, id)
首先是我所看到的人们使用最多的东西。但这迫使乐观者对每个
timestamp
分别进行id
范围搜索。因为每个id
可能都有不同的timestamp
值,所以您什么也得不到。第二个索引是我推荐的。
现在,乐观主义者可以非常迅速地完成你的问题的这一部分。。。
SELECT
o.*
FROM
orders
WHERE
orders.timestamp >= '2012-01-01'
AND orders.timestamp < '2012-02-01'
ORDER BY
orders.timestamp ASC
碰巧的是,甚至
ORDER BY
都用建议的索引进行了优化。它已经按照您希望输出数据的顺序。加入后不需要重新排序所有内容。然后,为了满足
total != '0.00'
的要求,您范围内的每一行都将被选中。但你已经把范围缩小了这么多,这样可能就没事了。(我不会深入讨论,但您可能会发现在MySQL中不可能使用索引来优化这个和timestamp
range seek。)那么,你就加入了。这是通过一个已经有
(products.order_id)
的索引优化的。对于上面代码片段挑选出的每个记录,乐观者可以进行索引查找,并非常快速地识别匹配的记录。这都假设,在绝大多数情况下,每个订单行都有一个或多个产品行。例如,如果只有极少数选定的订单具有任何产品行,那么首先选择感兴趣的产品行可能会更快;基本上是以相反的顺序查看连接。
乐观主义者实际上是为你做这个决定的,但是知道它在做这个决定是很方便的,然后提供你估计对它最有用的指数。
您可以检查解释计划,看看是否正在使用索引。如果没有,你的帮助尝试就被忽略了。可能是因为数据的统计暗示不同的连接顺序更好。如果是这样的话,那么您可以提供索引来帮助这种连接顺序。
关于mysql - MySQL查询优化-加入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12912914/