如何使用JOIN和BETWEEN where子句加快MYSQL查询?

时间:2020-03-21 08:02:33

标签: mysql sql performance join query-optimization

查询

SELECT SQL_CALC_FOUND_ROWS wp29174960179_posts.*
    FROM wp29174960179_posts
         JOIN wp29174960179_plugin_wpf_products_attribute_79_numbers pan ON pan.product_id = wp29174960179_posts.ID
    WHERE pan.number BETWEEN 10 and 10000
    ORDER BY wp29174960179_posts.post_date ASC LIMIT 0, 9; 

此查询很慢(耗时2秒)。 预期执行时间 <= 100ms

wp29174960179_plugin_wpf_products_attribute_79_numbers 表中有 80 000条记录

wp29174960179_posts 表中的 100,000条记录

wp29174960179_plugin_wpf_products_attribute_79_numbers 表有 2个索引

ix__number__product_id (product_id, number)
ix__product_id__number (number, product_id)

*wp29174960179_posts 索引 ID 字段

尽管有这些索引。查询需要 2-3

SQL完整代码段链接:

https://www.db-fiddle.com/f/4Vk97FhArBVJ1Eb1BAubNB/0#&togetherjs=8KQQacE4Vt

2 个答案:

答案 0 :(得分:3)

看起来 您在帖子和平移之间具有1-N的关系,并且您试图获取帖子中平移行中存在的满足给定条件的帖子。

如果是这样,您可以尝试使用EXISTS子查询来重写查询:

select p.*
from wp29174960179_posts p
where exists (
    select 1 
    from wp29174960179_plugin_wpf_products_attribute_79_numbers n 
    where n.product_id = p.id and n.number between 10 and 10000
)
order by p.post_date 
limit 9

此技术避免了在外部查询中进行聚合的需求。该查询应该能够利用wp29174960179_plugin_wpf_products_attribute_79_numbers(product_id, number)上的索引。

答案 1 :(得分:1)

我的猜测是外部排序导致了性能问题。您的查询和索引看起来很合理。问题是:我们可以欺骗MySQL避免排序吗?

从GMB建议的重写开始。它还具有不返回重复值的优点:

select p.*
from wp29174960179_posts p
where exists (select 1 
              from wp29174960179_plugin_wpf_products_attribute_79_numbers n 
              where n.product_id = p.id and
                    n.number between 10 and 10000
             )
order by p.post_date 
limit 9;

然后尝试以下索引:

  • wp29174960179_posts(post_date, id)
  • wp29174960179_plugin_wpf_products_attribute_79_numbers(product_id, number)

希望可以按post_date顺序扫描posts表,并返回前9个匹配的行。手指交叉。