mysql - MySQL查询优化-加入?

标签 mysql sql join query-optimization

一个给所有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中不可能使用索引来优化这个和timestamprange seek。)
那么,你就加入了。这是通过一个已经有(products.order_id)的索引优化的。对于上面代码片段挑选出的每个记录,乐观者可以进行索引查找,并非常快速地识别匹配的记录。
这都假设,在绝大多数情况下,每个订单行都有一个或多个产品行。例如,如果只有极少数选定的订单具有任何产品行,那么首先选择感兴趣的产品行可能会更快;基本上是以相反的顺序查看连接。
乐观主义者实际上是为你做这个决定的,但是知道它在做这个决定是很方便的,然后提供你估计对它最有用的指数。
您可以检查解释计划,看看是否正在使用索引。如果没有,你的帮助尝试就被忽略了。可能是因为数据的统计暗示不同的连接顺序更好。如果是这样的话,那么您可以提供索引来帮助这种连接顺序。

关于mysql - MySQL查询优化-加入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12912914/

相关文章:

python - 通过关键列合并一列的中位数 - SFrame/Pandas

php - 从 MySQL 数据库读取不起作用

MySQL - 选择过去 7 天的条目数

SQL Server 搜索 "ὡ"(U+1F61) 匹配所有内容?

mysql - 选择替换的选定结果的不同值

sql - 连接具有重复项的 SQL Server 表

php - 如何将非验证手机号码用户重定向到验证页面

mysql - 从转储文件恢复数据库时如何记录sql错误

mysql - 有没有办法将两个更新查询合并为一个?

php - 我想要特定月份+年份的所有玩家的最后一行